Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular 2 *ngFor, when iterable hasn't be instantiated yet

Tags:

angular

ngfor

I have a couple of *ngFor loops depending on iterables which might not be instantiated yet. (e.g. they are waiting for an observable)

is there any expression like this I could use in the view?

UPDATE: Here's the part thats throwing error

Component

activeLectureContent:LectureContent;

View

  <div class="filter-units">
    <div>Units</div>
    <a (click)="setUnit(i)" class="btn btn-icon-only blue filter-unit-btn" *ngFor="#unit of activeLectureContent.content; #i = index">
      <span>{{i+1}}</span>
    </a>
  </div>

Cannot read property 'content' of undefined in [null]

Lecture Content looks like this

export class LectureContent{
  constructor(
    public name:string = '',
    public filter:LectureFilter[]=[],
    public show:boolean = true,
    public hover:boolean = false,
    public content:any[]=[]
  ){}
}

cheers

like image 888
Han Che Avatar asked Apr 29 '16 21:04

Han Che


3 Answers

If it's "simply" an iterable (array, ... but not observable, promise), I think that there is nothing to do. ngFor will check for updates of the iterable. When the value will become not null, ngFor will update the corresponding content:

See this sample:

@Component({
  selector: 'app'
  template: `
    <div>
      <div *ngFor="#category of categories;#i=index">{{i}} - {{category.name}}</div>
    </div>
  `
})
export class App {
  constructor() {
    Observable.create((observer) => {
      setTimeout(() => {
        observer.next();
      }, 2000);
    }).subscribe(() => {
      this.categories = [
        { name: 'Cat1', value: 'cat1' },
        { name: 'Cat2', value: 'cat2' },
        { name: 'Cat3', value: 'cat3' },
        { name: 'Cat4', value: 'cat4' }
      ];
    });
  }
}

See this plunkr: https://plnkr.co/edit/J1aVclVcjJPqm1Qx9j0j?p=preview.

With beta 17, you need to replace # by let:

<div *ngFor="let category of categories;let i=index">{{i}} - (...)

It doesn't seem that ngIf with ngFor works well. See thisp plunkr: https://plnkr.co/edit/aE3umzzSZ5U9BocEE9l6?p=preview

If "iterable" is an observable or a promise, que the async pipe.

Edit

You could try something like that:

<template [ngIf]=" activeLectureContent ">
    <a (click)="setUnit(i)" class="btn btn-icon-only blue filter-unit-btn" *ngFor="#unit of activeLectureContent.content; #i = index">
      <span>{{i+1}}</span>
    </a>
</template>

I use the expanded syntax for ngIf since ngFor and ngIf can't be used on the same element.

like image 136
Thierry Templier Avatar answered Oct 26 '22 02:10

Thierry Templier


You could use an ngIf directive, so it is only rendered if iterable is thruthy.

<div *ngIf="iterable" *ngFor="let item of iterable"><div>
like image 44
rgvassar Avatar answered Oct 26 '22 03:10

rgvassar


Resurrecting this post as I recently had this same question.

This is a perfect case for Angular's (safe navigation operator).

From the docs:

The Angular safe navigation operator (?.) is a fluent and convenient way to guard against null and undefined values in property paths.

So the example view from the question would be:

  <div class="filter-units">
    <div>Units</div>
    <a (click)="setUnit(i)" class="btn btn-icon-only blue filter-unit-btn" 
      *ngFor="let unit of activeLectureContent?.content; let i = index">
      <span>{{i+1}}</span>
    </a>
  </div>

Adding the ? after activeLectureContent means the ngFor will be ignored if activeLectureContent is null or undefined.

like image 3
TyRo Avatar answered Oct 26 '22 02:10

TyRo