angular observables reading json into smart table - json

I am trying to read json data from a restFul server and populate a smart table with the results. I am stuck and cant seem to find out how to get it to work. It seems I am able to read the Json data from the restFul server but I am not real sure how to load it into the smart-table.
Any help is greatly appreciated!
Here are the parts of the application that are used:
the service (smart-table.service):
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { HttpErrorResponse, HttpResponse } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
export interface LCQIWK {
date: Date;
rank: number;
zone: string;
enodeb: string;
market: string;
usid: number;
impact: number;
tnol: number;
ret: number;
acc: number;
irat: number;
tput: number;
rtt: number;
}
const REST_SERVER = 'http://nonprod-hywrca02-zltv3747-0001- ingress.idns.cci.att.com:31840/thor';
// import { LCQIWK } from './models/lcqiwk';
#Injectable()
export class SmartTableService {
constructor(private http: HttpClient) { }
getData() {
return this.http.get<LCQIWK>(REST_SERVER + '/cqi/lte/wk')
.pipe(
retry(3), // retry a failed request up to 3 times
catchError(this.handleError) // then handle the error
);
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
// return an observable with a user-facing error message
return throwError(
'Something bad happened; please try again later.');
}
}
cqi-table.component
import { Component } from '#angular/core';
import { LocalDataSource } from 'ng2-smart-table';
import { LCQIWK, SmartTableService } from '../../../#core/data/smart-table.service';
// import { LCQIWK } from '../../../#core/data/models/lcqiwk';
#Component({
selector: 'app-cqi-table',
templateUrl: './cqi-table.component.html',
providers: [ SmartTableService ],
styleUrls: ['./cqi-table.component.scss']
})
export class CqiTableComponent {
settings = {
actions: false,
columns: {
date: {
title: 'Date',
type: 'number',
},
rank: {
title: 'Rank',
type: 'string',
},
zone: {
title: 'ZONE',
type: 'string',
},
enodeb: {
title: 'eNodeB',
type: 'string',
},
market: {
title: 'Market',
type: 'string',
},
usid: {
title: 'USID',
type: 'number',
},
impact: {
title: 'Impact',
type: 'number',
},
tnol: {
title: 'TNoL',
type: 'string',
},
ret: {
title: 'RET',
type: 'string',
},
acc: {
title: 'ACC',
type: 'string',
},
irat: {
title: 'IRAT',
type: 'string',
},
tput: {
title: 'TPUT',
type: 'number',
},
rtt: {
title: 'RTT',
type: 'number',
},
},
};
error: any;
headers: string[];
lcqiwk: LCQIWK;
source: LocalDataSource = new LocalDataSource();
constructor(private smartTableService: SmartTableService) {
this.smartTableService.getData()
.subscribe(
(data: LCQIWK) => this.lcqiwk = { ...data }, // success path
// this.source.load(this.lcqiwk),,
error => this.error = error, // error path
);
}
clear() {
this.lcqiwk = undefined;
this.error = undefined;
this.headers = undefined;
}
/* showConfig() {
this.smartTableService.getData()
.subscribe(
(data: LCQIWK) => this.lcqiwk = { ...data }, // success path
// this.source.load(this.lcqiwk),
error => this.error = error // error path
);
} */
}
// this.source.load(data);

Try this way...
this.smartTableService.getData()
.subscribe((data) => {
for (let i = 0; i < data.length; i++) {
data = {
id: (i + 1),
date : data[i].date,
rank : data[i].rank,
zone : data[i].zone,
enodeb : data[i].enodeb,
market : data[i].market,
usid : data[i].usid
// ... Add all data
}
this.source.add(data)
}
this.source.refresh();
});
}

Related

Problem on casting objects to array of a model in Angular

Here is my service code:
export class ProductListService {
constructor(private httpClient: HttpClient) {
}
getProducts(): Observable<IResponse> {
return this.httpClient.get<IResponse>('https://localhost:7127/Product/GetProductList');
}
}
and here is my component:
getProducts(): void {
this.productsService.getProducts()
.subscribe((response: IResponse) => {
this.products = <Product[]>response.data;
})
}
Which Product and IResponse are models:
export interface Product {
Id: string;
Title: string;
Description: string;
ImageUri: string;
CategoryId: string;
}
export interface IResponse {
data: object;
status: number;
}
When I get data from the api, it returns data as follow:
{
"data": [
{
"id": "e15",
"title": "LED TV 42 inch ",
"description": "-",
"imageUri": "C:\\wwwroot/cdn\\e15.jpg",
"categoryId": "tv"
},
{
"id": "e16",
"title": "LED TV 52 inch ",
"description": "-",
"imageUri": "C:\\wwwroot/cdn\\e16.jpg",
"categoryId": "tv"
}
],
"status": 200
}
I want to put the data into my products variable. How could I do this?
I agree with Sean Chase. Change the casing on your model. You also might want to cast the data property on the IResponse interface to Product[] (as a side note, interfaces don't start with I. That's a C# convention).
Are you using the products property in the template HTML? If so, you can use the pipe async syntax and replace the products property with an Observable<Product[]>. Here's an example
// models.ts
export interface Product {
id: string;
title: string;
description: string;
imageUri: string;
categoryId: string;
}
export interface IResponse {
data: Product[];
status: number;
}
// product-list.component.ts
import { Component, OnInit } from '#angular/core';
import { map, Observable, of, Subscription } from 'rxjs';
import { IResponse, Product } from './models';
import { ProductListService } from './products-list.service';
#Component({
selector: 'product-list',
template: `
<div *ngFor="let product of products$ | async">
<div>Id: {{ product.id }}</div>
<div>Title: {{ product.title }}</div>
<div>Description: {{ product.imageUri }}</div>
<div>CategoryId: {{ product.categoryId }}</div>
</div>
`
})
export class ProductListComponent implements OnInit {
products$: Observable<Product[]> = of([]);
constructor(private productsListService: ProductListService) {}
ngOnInit() {
this.products$ = this.productsListService.getProducts().pipe(map((res: IResponse) => res.data));
}
}
// product-list.service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, of } from 'rxjs';
import { IResponse, Product } from './models';
#Injectable({
providedIn: 'root',
})
export class ProductListService {
// constructor(private httpClient: HttpClient) {}
getProducts(): Observable<IResponse> {
// return this.httpClient.get<IResponse>('https://localhost:7127/Product/GetProductList');
return of({
data: [
{
id: '1',
title: 'title-1',
description: 'description-1',
imageUri: '/images/image-1.jpg',
categoryId: '1'
} as Product,
{
id: '2',
title: 'title-2',
description: 'description-2',
imageUri: '/images/image-2.jpg',
categoryId: '2'
} as Product,
],
status: 200
});
}
}

Angular 6 - Get current route and its data

How to get the current route you're in and its data, children and parent?
If this is the route structure:
const routes: Routes = [
{path: 'home', component: HomeComponent, data: {title: 'Home'}},
{
path: 'about',
component: AboutComponent,
data: {title: 'About'},
children: [
{
path: 'company',
component: 'CompanyComponent',
data: {title: 'Company'}
},
{
path: 'mission',
component: 'MissionComponent',
data: {title: 'Mission'}
},
...
]
},
...
]
If I am currently in CompanyComponent, how do I get my current route w/c is Company, get its parent w/c is about, its data and its siblings such as mission, etc.?
#Component({...})
export class CompanyComponent implements OnInit {
constructor(
private router: Router,
private route: ActivatedRoute
) {}
ngOnInit() {
// Parent: about
this.route.parent.url.subscribe(url => console.log(url[0].path));
// Current Path: company
this.route.url.subscribe(url => console.log(url[0].path));
// Data: { title: 'Company' }
this.route.data.subscribe(data => console.log(data));
// Siblings
console.log(this.router.config);
}
}
constructor(
private router: Router,
private route: ActivatedRoute,
) {
}
ngOnInit() {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
map(() => {
return this.getHeaderClasses();
}),
)
.subscribe((headerClasses: string | null) => {
this.headerClasses = headerClasses;
});
this.headerClasses = this.getHeaderClasses();
}
getHeaderClasses(): string | null {
let child = this.route.firstChild;
while (child) {
if (child.firstChild) {
child = child.firstChild;
} else if (child.snapshot.data && child.snapshot.data['headerClasses']) {
return child.snapshot.data['headerClasses'];
} else {
return null;
}
}
return null;
}
routing
{
path: 'list',
component: DialogListComponent,
data: {
headerClasses: 'col-lg-8',
},
},
You can access the route's data property from the snapshot like this:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
templateUrl: './app/home/welcome.component.html'
})
export class WelcomeComponent implements OnInit {
public pageTitle: string;
constructor( private route: ActivatedRoute) {
}
ngOnInit(): void {
this.pageTitle = this.route.snapshot.data['title'];
}
}
#Component({...})
#UntilDestroy()
export class CompanyComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit() {
this.router.events
.pipe(
untilDestroyed(this),
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
map((event: NavigationEnd) => event.url)
)
.subscribe(url=> {
console.log(url);
});
}
}

How to pass data received from service to angular datatable

I have just started working on Angular 4 and I am trying to render some data which I receive from angular service in json format, into angular-datatable, but whichever option i try its not working for me.
The table is coming, the columns are coming, however the data inside the columns are not displaying.
Any help would be great,
Thanks in advance..!!!!
Please find my code below:
component.html
<table datatable [dtOptions]="dtOptions" class="row-border hover"></table>
component.ts
import { Component, OnInit } from '#angular/core';
import { FleetDataService } from '../../services/fleet-data.service';
import { Subject } from 'rxjs/Subject';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
private fleetData: any;
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
constructor(private getFleetData:FleetDataService) { }
ngOnInit() {
this.getFleetData.getFleetData().subscribe(
fleetData => {
this.fleetData = fleetData;
console.log(this.fleetData);
this.dtTrigger.next();
},
err => {
console.log(err);
}
);
this.dtOptions = {
pagingType: 'full_numbers',
columns: [{
title: 'First Name',
data: this.fleetData
}, {
title: 'Last Name',
data: this.fleetData
}, {
title: 'Score',
data: this.fleetData
}]
};
}
}
component.service
import { Injectable } from '#angular/core';
import { HttpModule, Http, Response, Headers, RequestOptions } from
'#angular/http';
import { Observable } from 'rxjs/Rx';
#Injectable()
export class FleetDataService {
constructor(private http: Http) { }
getFleetData() {
return this.http.get("../../assets/data/test.json")
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server
Error'));
}
}
test.json
[{
"FirstName": "Jill",
"LastName": "Smith",
"Score": "disqualified"
}, {
"FirstName": "Eve",
"LastName": "Jackson",
"Score": "94"
}, {
"FirstName": "John",
"LastName": "Doe",
"Score": "80"
}, {
"FirstName": "Adam",
"LastName": "Johnson",
"Score": "67"
}]
You set your dtOptions outside the subscribe.
If you do this the fleetData stays empty so dtOptions is never set correctly, because an Observable is asynchronous. I propose this code:
export class DashboardComponent implements OnInit {
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
constructor(private getFleetData:FleetDataService) { }
ngOnInit() {
this.getFleetData.getFleetData().subscribe(
fleetData => {
console.log(fleetData);
this.buildDtOptions(fleetData)
this.dtTrigger.next();
},
err => {
console.log(err);
});
}
private buildDtOptions(fleetData: any): void {
this.dtOptions = {
pagingType: 'full_numbers',
columns: [
{title: 'First Name', data: fleetData},
{title: 'Last Name', data: fleetData},
{title: 'Score', data: fleetData}
]
};
}
}
For this error: ERROR TypeError: Cannot read property 'aDataSort' of undefined. You can do a spinner (ngIf / else) in the view and when data are loaded you display the datatable

JSON data with angular2-highcharts

I want to create chart based on the JSON data.
I using angular2-highcharts my ChartsMain component looks like:
#Component({
moduleId: module.id,
selector: 'charts',
templateUrl: 'charts.html',
directives: [CHART_DIRECTIVES,]
providers: [DataService]
})
export class ChartsMain {
result: Data[];
constructor(DataService:DataService) {
DataService.getData().subscribe(res => this.result = res);
this.options = {
chart: {
type: "candlestick"
},
title: {
text: "JSON data"
},
xAxis: {
type: "category",
allowDecimals: false,
title: {
text: ""
}
},
yAxis: {
title: {
text: "Number"
}
},
series: [{
name: "Hour",
data: this.result
}]
};
}
options: Object;
And my DataService looks:
#Injectable()
export class DataService {
http: Http;
constructor(http: Http) {
this.http = http;
}
getData(): Observable<Array<Data>> {
return this.http.get('http://JSON-DATA')
.map(this.extractData)
.catch(this.handleError)
}
private extractData(res: Response) {
let body = res.json();
return body || { };
}
private handleError(error: any) {
// In a real world app, we might use a remote logging infrastructure
// We'd also dig deeper into the error to get a better message
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead
return Observable.throw(errMsg);
}
}
My chart
Where is a problem, why is chart empty? How do I fill the chart with JSON data. JSON data must be in any specific format?
A candlestick chart is typically used to present the open, high, low and close price over a period of time..
Sample expected JSON format looks like this-
[
[1250553600000,23.09,23.46,23.06,23.43],
[1250640000000,23.25,23.61,23.21,23.51],
[1250726400000,23.57,23.82,23.52,23.76],
[1250812800000,23.95,24.20,23.83,24.17],
[1251072000000,24.30,24.39,24.04,24.15],
[1251158400000,24.21,24.42,24.16,24.20],
[1251244800000,24.13,24.22,23.82,23.92],
[1251331200000,24.11,24.22,23.55,24.21],
[1251417600000,24.61,24.64,24.08,24.29],
[1251676800000,24.02,24.12,23.79,24.03],
]
Here is sample component with candlestick highchart-
import { Component } from '#angular/core';
import {JSONP_PROVIDERS, Jsonp} from '#angular/http';
import { CHART_DIRECTIVES } from 'angular2-highcharts';
#Component({
selector: 'high-chart',
directives: [CHART_DIRECTIVES],
providers: [JSONP_PROVIDERS],
template: `
<h2> This is HighChart CandleStick component </h2>
<chart type="StockChart" [options]="options3"></chart>
`
})
export class HighChartsComponent {
options3: Object;
constructor(jsonp : Jsonp) {
jsonp.request('https://www.highcharts.com/samples/data/jsonp.php?a=e&filename=aapl-ohlc.json&callback=JSONP_CALLBACK').subscribe(res => {
this.options3 = {
title : { text : 'CandleSticks' },
rangeSelector : {
selected : 1
},
series : [{
type : 'candlestick',
name : 'CandleSticks',
data : res.json(),
dataGrouping : {
units : [
[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]
]
},
tooltip: {
valueDecimals: 2
}
}]
};
});
}
EDIT:
In your case you are not setting chart options inside subscribe. You should set like this-
this._http.get('http://knowstack.com/webtech/charts_demo/data.json')
.map(this.extractData)
.subscribe((response) => {
this.options = {
title : { text : 'knowstack' },
series : [{
name : 'knowstack',
data : response.json()
}]
};
},
(error) => {
this.errorMessage = <any>error
});
Please note - data from knowstack will only work with simple charts (not candlestick)
EDIT 2: column chart
Please refer below configuration. This is how you can use column chart.
this.options1 = {
title : { text : 'simple column chart' },
series: [{
type : 'column',
data: [["Maths",15],["Physics",16],["Biology",18],["Chemistry",19]]
}]
};
EDIT 3: sample of key-value pair json
import { Component } from '#angular/core';
import { CHART_DIRECTIVES } from 'angular2-highcharts';
#Component({
selector: 'my-app',
directives: [CHART_DIRECTIVES],
styles: [`
chart {
display: block;
}
`]
template: `<chart [options]="options"></chart>`
})
class AppComponent {
constructor() {
var data = [{"key":"Math","value":98},{"key":"Physics","value":78},{"key":"Biology","value":70},{"key":"Chemistry","value":90},{"key":"Literature","value":79}];
this.options = {
title : { text : 'simple chart' },
xAxis: {
type: 'category'
},
series: [{
data: data.map(function (point) {
return [point.key, point.value];
})
}]
};
}
options: Object;
}
Ok it is work. I use service which in my first post, I just changed component: constructor(http: Http, jsonp : Jsonp, DataService:DataService) {
DataService.getData().subscribe(res => this.result = res);
http.request('').subscribe(res => {
this.options = {
chart: {
type: 'column'
},
plotOptions: {
column: {
zones: [{
value: 12,
},{
color: 'red'
}]
}
},
series: [{
data: this.result
}]
};
});
}
options: Object;
in this case json data: [{"key":"Math","value":98},{"key":"Physics","value":78},{"key":"Biology","value":70},{"key":"Chemistry","value":90},{"key":"Literature","value":79}]
How can I split this data like there http://www.knowstack.com/webtech/charts_demo/highchartsdemo4.html

aurelia bridge kendo grid refresh

I'm trying to use Aurelia KendoUi Bridge in my application.
In my code I have a service which returns a new KendoDataSource :
export class KendoDataSource {
ToKendoDataSource(data: any, recordCount: number, pageSize: number, currentPage: number): any {
return {
transport: {
read: (p) => {
p.success({ data: data, recordCount: recordCount });
}
},
pageSize: pageSize,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
schema: {
data: (result) => {
console.log('Transforming data to kendo datasource.');
return result.data;
},
total: (result) => {
return result.recordCount;
}
}
};
}
}
And this is my viewModel:
#inject(HttpService, KendoDataSource, EventAggregator)
export class GroupList {
grid: any;
gridVM: any;
datasource: any;
pageable: any;
subscriber: any;
paginationDetailsRequest: PaginationDetailsRequest;
test: string;
constructor(private httpService: HttpService, private kendoDataSource: KendoDataSource, private eventAggregator: EventAggregator) {
this.httpService = httpService;
this.kendoDataSource = kendoDataSource;
this.eventAggregator = eventAggregator;
this.paginationDetailsRequest = new PaginationDetailsRequest(4, 1);
this.GetGroups(this.paginationDetailsRequest);
this.datasource = {
transport: {
read: {
url: 'PersonGroup/GetGroups',
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json'
},
parameterMap: function (data, type) {
if (type == "read") {
let paginationDetails = new PaginationDetailsRequest(data.pageSize, data.page);
if(data.sort && data.sort.length > 0){
paginationDetails.orderBy = data.sort[0].field;
paginationDetails.OrderDesc = (data.sort[0].dir == 'desc');
}
console.log(this.datasource);
return JSON.stringify(paginationDetails);
}
}
},
schema: {
data: "data.currentPageData",
total: "data.totalCount"
},
pageSize: 2,
serverPaging: true,
serverFiltering: true,
serverSorting: true
};
};
attached() {
this.subscriber = this.eventAggregator.subscribe('Search', response => {
this.search(response);
});
}
activate() {
this.pageable = {
refresh: true,
pageSizes: true,
buttonCount: 10
};
}
GetGroups(paginationDetails: PaginationDetailsRequest): void {
this.httpService.post('PersonGroup/GetGroups', paginationDetails)
.then(response => response.json())
.then(groups => {
console.log(groups);
if (groups.succeeded) {
this.datasource = this.kendoDataSource.ToKendoDataSource(groups.data.currentPageData, groups.totalCount, groups.pageSize, groups.currentPage);
this.grid.setDataSource(this.datasource); // initialize the grid
}
else {
//TODO: Show error messages on screen
console.log(groups.errors);
}
})
.catch(error => {
//TODO: Show error message on screen.
console.log(error);
});
}
search(searchDetails: Filter) {
console.log(searchDetails);
this.paginationDetailsRequest.filters.push(searchDetails);
console.log(this.paginationDetailsRequest);
this.GetGroups(this.paginationDetailsRequest);
}
detached() {
this.subscriber.dispose();
}
}
I understand that kendo does not have two-way data binding, But I'm trying to find a way to refresh the grid when I filter the data and the data source has changed.
Thanks.
I had this problem and found the solution by creating a new dataSource and assigning it to setDataSource, as follows... Note, getClients() is a search activated by a button click.
Here is the grid:
<ak-grid k-data-source.bind="datasource"
k-pageable.bind="{ input: true, numeric: false}"
k-filterable.bind="true"
k-sortable.bind="true"
k-scrollable.bind="true"
k-widget.bind="clientgrid"
k-selectable.bind="true">
<ak-col k-title="First Name" k-field="firstName" k-width="120px"></ak-col>
<ak-col k-title="Last Name" k-field="lastName" k-width="120px"></ak-col>
<ak-col k-title="Email Address" k-field="primaryEmail" k-width="230px"></ak-col>
</ak-grid>
And here is the code that updates the dataSource
public getClients()
{
console.log("ClientService.getClients");
this.clientService.getClients()
.then(result =>
{
this.clientList = result;
// the new datasource in the next line is displayed
// after the call to setDataSource(ds) below.
let ds: kendo.data.DataSource = new kendo.data.DataSource({
data: this.clientList,
schema: {
model: {
id: "id",
fields: {
firstName: { type: 'string' },
id: { type: 'number' },
lastName: { type: 'string' },
primaryEmail: { type: 'string' }
}
}
},
pageSize: 10
});
this.clientgrid.setDataSource(ds);
this.clientgrid.refresh();
})
.catch(err => console.log("Error returned from getClients " + err));
}
You don't really need to create a brand new datasource. To refresh the grid after changing the underlying data you can just replace the data element in the dataSource like so:
this.clientgrid.dataSource.data(this.datasource.data);