Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - TypeError: Cannot read property 'Id' of undefined in (Typescript)

I'm getting the following error:

angular2.dev.js:23925 EXCEPTION: TypeError: Cannot read property 'Id' of null in [


{{ product.Id }}
 in ProductEditComponent@0:68]

thrown with:

//Product-edit.component.ts:

import {Component } from 'angular2/core';
import { IProduct } from './product'
import { ProductService } from './product.service'
import { RouteParams } from 'angular2/router';
@Component({
  template:`<div class="wrapper wrapper-content animated fadeInRight ecommerce"> 
              {{ product.Id }}
            </div>`, 
})
export class ProductEditComponent{
    product: IProduct = null;
    errorMessage: string;
    constructor(private _routeParams: RouteParams, private _productService: ProductService){

    }

    ngOnInit(): void {
        this._productService.getProduct(this._routeParams.get('id'))
            .subscribe(
                product => this.product = product,
                error => this.errorMessage = <any>error);


    }

}

ProductService:

getProduct(id: string): Observable<IProduct> {
    return this._http.get(this._baseUrl + this._getProductUrl + '/' + id)
        .map((response: Response) => <IProduct>response.json())
        .do(data => console.log("All: " + JSON.stringify(data)))
        .catch(this.handleError);
}

Response from server:

{"Id":"34d4efcy6","ExternalId":null,"UserId":"testing","ProductProvider":null,"Title":"Flaska vin","Desc":null,"MinDeliveryTime":null,"MaxDeliveryTime":null,"FreightCost":null,"Brand":null}

What am I messing up?

like image 212
Niklas Avatar asked May 08 '16 00:05

Niklas


1 Answers

In your component, you're initializing product to null, and then referencing product.Id in your template. The error occurs when Angular tries to draw your template initially, before your async call returns - at which point product is still null, thus the error: Cannot read property 'Id' of null.

The most immediate solution is to use the Elvis operator, which Angular provides for situations precisely like this. You'd use it by replacing {{ product.Id }} with {{ product?.Id }} in your template.

That said, you're likely to run into change detection problems with this approach, and in general you'll be much better off with an approach like:

export class ProductEditComponent{
  product: Observable<IProduct>; //product is an Observable
  errorMessage: string;
  constructor(private _routeParams: RouteParams, private _productService: ProductService){
     //product is always defined because you instantiate it in the ctor
     this._productService.getProduct(this._routeParams.get('id'));
  }

You'd then use {{(product | async).Id }} in place of {{product.Id}} in your template, leveraging AsyncPipe to let angular handle the dirtywork of subscribing and updating the UI as needed for you.

like image 171
drew moore Avatar answered Oct 21 '22 18:10

drew moore