I have in my angular5 application a component called product-list.component.ts
. In this component I have a constructor, which calls a REST API. I've put this code in the constructor, because the constructor gets loaded first.
product.service.ts
getAllProductsFromACategory(categoryName: string): any {
this.http.get('http://localhost:8080/VespaWebshopAPI
/api/Article/Category?categoryName=' + categoryName).
subscribe(data => {
var article: Article = {
id: data[0].id,
name: data[0].name,
articleNr: data[0].articleNr,
stock: data[0].stock,
price: data[0].price,
description: data[0].description
};
return article;
});
product-list.component.ts
public article: Article;
constructor(private route: ActivatedRoute,
private productService: productService) {
//Call rest api
this.article =
this.productService.getAllProductsFromACategory('Bremsen');
}
article.ts
export interface Article {
id : number;
name : string;
articleNr : string;
stock : number;
price : number;
description : string;
}
In my html, I want to display some properties of an article. So if I try to run this code in my product-list.component.html file, I get following error:
{{ article.id }}
Error
ProductListComponent.html:1 ERROR TypeError: Cannot read property 'id' of undefined
at Object.eval [as updateRenderer] (ProductListComponent.html:1)
at Object.debugUpdateRenderer [as updateRenderer] (core.js:14727)
at checkAndUpdateView (core.js:13841)
at callViewAction (core.js:14187)
at execComponentViewsAction (core.js:14119)
at checkAndUpdateView (core.js:13842)
at callViewAction (core.js:14187)
at execEmbeddedViewsAction (core.js:14145)
at checkAndUpdateView (core.js:13837)
at callViewAction (core.js:14187)
The REST API works; I tested it. I guess there is just the problem that the data should get loaded first, before the html page gets displayed. Somewhere else I read that in an ngFor
, I should make use of the | async pipe, but that didn't work for me.
So how do I solve this?
In
productService.getAllProductsFromACategory()
replacesubscribe
withmap
so that the method returnsObservable<Article>
In
constructor
ofproduct-list.component.ts
, subscribe to theObservable<Article>
returned fromproductService
and set value forthis.article
in thatIn your html, put an
*ngIf="article"
in the surrounding element of your interpolation{{ article.id }}
to prevent it from processing untilarticle
obtains a valid value.@TNII, @Hoang Duc, try say you is that generally a service expose Observables. It's in a ngOnInit in your component when you subscribe to the Observable.
In the component, generally in an ngOnInit when we subscribe to
the {{article?.id}} wrote in the html is a abreviate way to say: if this.article is defined, show me this.article.id.
check if when in a navigator write http://localhost:8080/VespaWebshopAPI /api/Article/Category?categoryName='Bremsen', give you an array of Articles. Check if the elements of the arrays has properties id,name,etc (or return element with another properties)
The problem is that the template is trying to use a data which is not available yet. Before accessing it, the server's response must be completed. So, in order "to wait and avoid that error", i did a similar trick that worked fine.
I wrote a conditional directive on the surronding element. Doing that, "while data_from_server is null", template does not try to get the info and does not produce the fail.