80

I have a question about checking if some field in object exists.

I want to print all categories which user has so I'm doing something like this:

  <ul *ngIf="user.categories.length >  0" *ngFor="#category of user.categories">
    <li>
      {{category.name}}
    </li>
  </ul>

The reason? All the data are PROPERLY printed, but I'm getting an error in web console like this:

Cannot read property 'name' of null

But when I do something like:

  <ul *ngIf="user.categories.length >  0" *ngFor="#category of user.categories">
    <li *ngIf="category">
      {{category.name}}
    </li>
  </ul>

Then all is okay.

Am I doing something wrong or maybe I have to check this every time? Have you ever had a problem like this one?

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
elzoy
  • 5,237
  • 11
  • 40
  • 65

1 Answers1

217

basic usage

Use the safe-navigation operator

{{category?.name}}

then name is only read when category is not null.

array

This only works for the . (dereference) operator. For an array you can use

{{records && records[0]}}

See also Angular 2 - Cannot read property '0' of undefined error with context ERROR CONTEXT: [object Object]

async pipe

With async pipe it can be used like

{{(chapters | async)?.length

ngModel

With ngModel currently it needs to be split into

[ngModel]="details?.firstname" (ngModelChange)="details.firstname = $event"

See also Data is not appending to template in angular2

*ngIf

An alternative is always to wrap the part of the view with *ngIf="data" to prevent the part being rendered at all before the data is available to prevent the dereference error.

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Yup, doesn't work for `ngModel` bindings. Still missing the Angular1's auto generated properties which were extremely handy for client-server CRUD operations. –  Apr 22 '16 at 23:07
  • @Hani I don't know Angular1. Can you point me to some information about auto generated properties? – Günter Zöchbauer Apr 23 '16 at 10:14
  • `` and the name being null would auto generate the name property as soon as user types in the textbox. Not to mention that elvis operator doesn't work for `[(ngModel)]`. Would be nice to have it there too. –  Apr 23 '16 at 19:55
  • They discussed recently to make elvis operator behavior the default. Likely they'll make some improvment. Probably not too soon. – Günter Zöchbauer Apr 23 '16 at 19:58
  • I get why `category?.name` is a suitable replacement for doing `*ngIf="category"`, but why do you have to check for it to exist at all? It exists or `*ngIf` would not be true and we wouldn't get a list printed. I'm experiencing this as well so I'm not questioning the solution - it works - I just don't understand why it is required. What is occurring that means there is a null category at some point? – WillyC Sep 14 '16 at 15:41
  • Exactly, in this example `?.` is only relevant for `null` categories. – Günter Zöchbauer Sep 14 '16 at 15:46
  • OK - well take for example section 5.18 of this tutorial: http://www.angular-meteor.com/tutorials/socially/angular2/routing-and-multiple-views In that last template section if I omit the `*ngIf` I get the `Cannot read property` error, but it is fine if I add it. There is only one `party`, not a list where one might be `null` (at least from what I can see). This may be some oddity that I'm not used to from Meteor but it doesn't make a lot of sense on the surface. – WillyC Sep 14 '16 at 15:56
  • This is usually when `party` is acquired asynchronically. When Angular renders the view the first time, `party` is still `null` and `party.name` throws. With `*ngIf="party"` only when `party` becomes `!= null`, then this part of the view is added to the DOM and the bindings are resolved and there is no error because this part only is evaluated after Angular ensured `part != null`. – Günter Zöchbauer Sep 14 '16 at 16:00
  • Thanks! Makes sense. Seems kind of inefficient that with even such a simple page it renders more than once, but I guess I'll have to learn a bit more before I worry about that. – WillyC Sep 14 '16 at 16:03
  • The page doesn't render again. Just the part that was excluded previously by `*ngIf` gets added when the expression becomes true. – Günter Zöchbauer Sep 14 '16 at 16:11
  • 3
    I was looking for this answer but is hard to find angular2-4 answers. Thank you is so simple and works well! – Mikel Jun 09 '17 at 10:24
  • if the value has another level like category-->name-->rating then simply do this {{category?.name?.rating}} – skydev Aug 29 '18 at 13:44