Tony
Tony

Reputation: 1694

Angular 2 Simple HTTP Get

I am trying to learn angular 2 and I cannot get the most simple http get to work.

I get the runtime error

 Cannot read property 'id' of undefined

But at the same time the value of 'id' is being shown on the page which confuses me a lot. How can it be undefined and still be shown.

I get this json returned from the WebApi

{
"category":["some string"],
"icon_url":"some string",
"id":"some string",
"url":"some string",
"value":"some string"
}

I have created an interface

export interface IProduct {
category: string;
icon_url: string;
id: string;
url: string;
value: string;
}

In my service I have this method that call the webApi and returns the json

getproducts(context: ContentAndStructureContext): Observable<IProduct[]> {
return this.http.get(routes.url(context), { cache: true })
  .map((res: Response) => <IProduct[]>res.json())
  .do(data => console.log(data));

}

That works fine and the data object is being logged to the console. So far so good

in my component I have call the getProducts method

export class HomeComponent implements OnInit {
 isProductLoading: boolean;
 iproducts: IProduct[]; 

constructor(private contentAndStructureService: ContentAndStructureService) {}

 ngOnInit() {
this.isLoading = true;
this.isProductLoading = true;    

  this.contentAndStructureService.getproducts({ category: 'dev' })
  .pipe(finalize(() => { this.isProductLoading = false; }))
  .subscribe(iproducts => this.iproducts = iproducts);
 }
}

This is my HTML. It prints the value of the iproducts.id just fine.

<div class="container">
  <mat-card>     
    <mat-card-content>     
      <mat-card-subtitle>
        <app-loader [isLoading]="isProductLoading" size="1.5"></app-loader>
        <q [hidden]="isProductLoading">{{iproducts.id}}</q>
      </mat-card-subtitle>
    </mat-card-content>
  </mat-card>
</div>

BUT in the console the follow error gets logged

ERROR TypeError: Cannot read property 'id' of undefined
at Object.eval [as updateRenderer] (home.component.html:13)
at Object.debugUpdateRenderer [as updateRenderer] (core.js:14377)
at checkAndUpdateView (core.js:13513)
at callViewAction (core.js:13858)
at execComponentViewsAction (core.js:13790)
at checkAndUpdateView (core.js:13514)
at callViewAction (core.js:13858)
at execEmbeddedViewsAction (core.js:13816)
at checkAndUpdateView (core.js:13509)
at callViewAction (core.js:13858)

I dont understand how the id can be undefined and at the same time the value get printed just fine ... and i dont know how to fix it. I have spend countless hours on this and hope someone has time to show me what i do wrong here.

Upvotes: 0

Views: 58

Answers (1)

rayepps
rayepps

Reputation: 2092

I think you have two problems. First is async. Heres a timeline of whats happening

  1. The component is initialized
  2. The constructor is called
  3. The on init method is called
  4. The on init method sends the http request......
  5. The on init completes
  6. The view is initialized and the iproducts.id is called

some time later......

  1. The http request completes and the subscribe call back is called setting your iproducts

So, when your view initializes and your template is run iproducts is still null because your http request hasn’t finished yet. I would either wrap that part of the template in an if ngIf=“iproducts” or give iproducts a default value that wont cause an error when properties are accessed.

The second issue is you have an array and your trying to access an id on it..... I think you want use an ngFor=“let iprod of iproducts” to iterate the items in the array then say iprod.id.

You’ll still need to either check to make sure iproducts isn’t null or give it a default value of []

Upvotes: 1

Related Questions