Chuck Tung Chuck Tung - 6 months ago 21
TypeScript Question

angular class method not working when populated by service

I'm learning Angular 4 and I can't figure out how to get class methods to work.

I have a class for the feature, that includes some methods that allow constructing a google charts JSON datatable.

export class Feature {
id: string;
name: string;

get cols() {
return [
{'id': '', 'label': 'id', 'type': 'string'},
{'id': '', 'label': 'name', 'type': 'string'}
];
}

get row() {
console.log('foo');
return {'c': [ {'v': this.id}, {'v': this.name} ] };
}

}


I have a service that populates the features from a REST API:

import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';

import 'rxjs/add/operator/toPromise';
import { Feature } from './feature';

@Injectable()
export class FeatureService {
private featureUrl = 'http://raspi/rest/api';

constructor(private http: Http) { }

getFeatures(): Promise<Feature[]> {
return this.http.get(this.featureUrl + '/getFeatures')
.toPromise()
.then(response => response.json().results as Feature[])
.catch(this.handleError);
}

private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
}


Then in my component, on init, I call the service, and attempt to convert the instance array into a Google datatable:

import { Component, OnInit } from '@angular/core';
import { Feature } from '../feature';
import { FeatureService } from '../feature.service';

@Component({
selector: 'app-features',
templateUrl: './features.component.html',
styleUrls: ['./features.component.css']
})
export class FeaturesComponent implements OnInit {
features: Feature[];

public tableData = {
chartType: 'Table',
dataTable: {},
options: {'title': 'Tasks'},
};

constructor(
private featureService: FeatureService
) { }

private features2dataTable(features: Feature[]) {
const data = {
'cols': [],
'rows': []
}

features.forEach(function(feature) {
console.log(feature);
data.cols = feature.cols;
data.rows.push( feature.row );
});
console.log(data);
return data;
}

getFeatures(): void {
this.featureService
.getFeatures()
.then(features => this.tableData.dataTable = this.features2dataTable(features))
}

ngOnInit(): void {
this.getFeatures();
}

}


I want the datatable to have this format:

{
"cols": [
{"id":"","label":"Topping","pattern":"","type":"string"},
{"id":"","label":"Slices","pattern":"","type":"number"}
],
"rows": [
{"c":[{"v":"Mushrooms","f":null},{"v":3,"f":null}]},
{"c":[{"v":"Onions","f":null},{"v":1,"f":null}]},
{"c":[{"v":"Olives","f":null},{"v":1,"f":null}]},
{"c":[{"v":"Zucchini","f":null},{"v":1,"f":null}]},
{"c":[{"v":"Pepperoni","f":null},{"v":2,"f":null}]}
]
}


but when I use feature.row or feature.cols, I get back undefined, even though the "id" and "name" fields of the instance are populated:

{id: "BP01", name: "BP feature one"}
id: "BP01"
name: "BP feature one"
__proto__: Object
features.component.ts:30

{id: "BP02", name: "BP feature two"}
id: "BP02"
name: "BP feature two"
__proto__: Object
features.component.ts:34

{cols: undefined, rows: Array(2)}
cols: undefined
rows: (2) [undefined, undefined]
__proto__: Object


Why won't the get method work?

Answer Source

Doing...

.then(response => response.json().results as Feature[])

does not actually create an array of Feature objects, therefore you do not have access to any class specific methods, since they are just POJO's.

You need to explicitly make the objects instances of your class, so something like this:

getFeatures() {
  return this.http.get(this.featureUrl + '/getFeatures')
    .toPromise()
    .then(response => response.json().results.map(obj => Object.assign(new Feature(), obj)))
    .catch(this.handleError);
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download