angular2: Error: TypeError: Cannot read property '...' of undefined

130.5k views Asked by At

I have attached the plunker of my angular2 code piece. I want to print a field from my JSON but unable to print that as initially my Object is null and it is being populated via a Promise.

This is my component file

import {Component, NgModule, OnInit} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

class MyData {
  xyz : MySubData;
}

class MySubData {
  name : string;
} 
@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>

      {{abc.xyz.name}}
    </div>
  `,
})
export class App implements OnInit {
  abc : MyData = null;
  constructor() {
    this.name = 'Angular2'
  }

  ngOnInit() {
    setTimeout(() => {
      this.abc = new MyData();
      this.abc.xyz = new MySubData();
      this.abc.xyz.name = "Binita";
    }, 2000);
  }
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

When I am removing the line {{abc.xyz.name}} from my template it is running fine.

I have use set time out in my code because I am getting my data from Promise (i.e asynchronous call).

I can understand initially as abc is null, my code is unable to find abc.xyz.name. But I don't want to put any if condition to check. Because I have several property inside a JSON and it is not possible for each property to write if condition.

Earlier in angularjs 1 if abc is null then it would automatically replace it with blank string. I want to do the same thing in angular2. Please suggest.

Below is the plunker

https://plnkr.co/edit/u1NqNF0penz7OS55QmoU?p=preview

3

There are 3 answers

0
Stefan Svrkota On BEST ANSWER

That's because abc is undefined at the moment of the template rendering. You can use safe navigation operator (?) to "protect" template until HTTP call is completed:

{{abc?.xyz?.name}}

You can read more about safe navigation operator here.

Update:

Safe navigation operator can't be used in arrays, you will have to take advantage of NgIf directive to overcome this problem:

<div *ngIf="arr && arr.length > 0">
    {{arr[0].name}}
</div>

Read more about NgIf directive here.

0
Ali Eshghi On

the best way in angular is utilizing resolver guard. this guard help you get data before rendering view, while now you rendering data first then you get data, that's why you face with such an error. I prepare a video on YouTube, you can get idea there. follow this video

0
Jiping On

Safe navigation operator or Existential Operator or Null Propagation Operator is supported in Angular Template. Suppose you have Component class

  myObj:any = {
    doSomething: function () { console.log('doing something'); return 'doing something'; },
  };
  myArray:any;
  constructor() { }

  ngOnInit() {
    this.myArray = [this.myObj];
  }

You can use it in template html file as following:

<div>test-1: {{  myObj?.doSomething()}}</div>
<div>test-2: {{  myArray[0].doSomething()}}</div>
<div>test-3: {{  myArray[2]?.doSomething()}}</div>