问题
I'm using Angular 8 and am trying to do something that seems like it should be really simple.
I'm retrieving an array of records from my controller on the server using http.get. Those records have a particular type (defined within Angular) and I would like to add a computed property to that type called "meetsTarget". My problem is that it is not recognising that that property exists on the results I get back from the server.
Question 2: Becasue that property is computed from other properties, I would also like it to be updated (and those updates be automatically picked up in the html) when those other properties change.
Here is my component:
import { Component, Inject } from '@angular/core';
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from "@angular/router";
import { Globals, KPIEntry } from './../../globals';
@Component({
selector: 'app-enter-toller',
templateUrl: './enter-toller.component.html',
styleUrls: ['./enter-toller.component.css']
})
export class EnterTollerComponent {
public data: KPIEntry[];
constructor(private route: ActivatedRoute, private http: HttpClient, @Inject('BASE_URL') private baseURL: string, private gl: Globals, private location: Location) {
// get results from the server
this.http.get<KPIEntry[]>(this.baseURL + 'api/KPIEntry/ListTollerKPI/1').subscribe(result => {
this.data = result;
console.log(this.data);
}, error => console.error(error));
}
}
My problem with the above code is that when I log this.data to the console, I can see all the results from the server but it doesn't show my computed property called "meetsTarget".
KPIEntry (along with my computed property "meetsTarget") is defined in globals.ts:
export class KPIEntry {
id: number;
kpiName: string;
mtd: number;
ytd: number;
targetYTD: number;
kpiComparisonType: string;
get meetsTarget(): boolean {
if (this.kpiComparisonType == "gteq") {
return (this.ytd >= this.targetYTD);
}
if (this.kpiComparisonType == "lteq") {
return (this.ytd <= this.targetYTD);
}
}
}
As you can see, meetsTarget is a readonly property that depends on kpiComparisonType, ytd and targetYTD. It will be possible to change both ytd and targetYTD using the component above and so the result for meetsTarget should be something that is dynamically updated if either of those values change.
My first problem though is that I cannot even get "meetsTarget" to be recognised as a property of the records in my result set.
I'd appreciate anyone who can point me in the right direction.
Thanks!
回答1:
this.http.get<KPIEntry[]>
This tells TypeScript: trust me, this call will return an Observable<KPIEntry[]>
.
It does not tell: please, take the JSON from the server and parse it to an array of KPIEntry
.
What the HttpClient does with the JSON response body it gets is extremely simple: it calls JSON.parse()
. Parsing JSON will never, ever produce an instance of your class. The JSON parser doesn't know that your class exists and doesn't care about it. It simply creates plain old JavaScript objects which have the same structure as the JSON.
So when you do
this.http.get<KPIEntry[]>
you're only lying to the compiler and to yourself.
If you want to have instances of KPIEntry
, you need to create them, by calling the class constructor. So you need to transform every POJO in the array actually emitted by the observable into an instance of KPIEntry
.
来源:https://stackoverflow.com/questions/57543544/trying-to-add-a-computed-property-to-a-result-set-from-a-controller-in-angular