4

TL;DR:
Angular raises ExpressionChangedAfterItHasBeenCheckedError when using an iterator with ngFor.


I have a template which uses ngFor like:

<div *ngFor="let something of foobarIterator()">

The TypeScript code being like:

private foobar = [];

public foobarIterator() {
    return this.foobar[Symbol.iterator]();
}

According to Angular documentation it is allowed to pass an iterator to ngForOf and it actually works… except it throws an ExpressionChangedAfterItHasBeenCheckedError afterwards.

While I understand that it may be because I return a new instance of iterator every time the method is called, I do not get what Angular expects instead. Using the same instance of the iterator after it has been exhausted makes no sense – it's an iterator after all, not the array itself.

What is the correct way of using iterators with ngFor then?

jaboja
  • 2,178
  • 1
  • 21
  • 35

1 Answers1

2

This problem has been discussed and solutions proposed several times .. although not too easy to find.

Angular 6.1.0 finally provides a new pipe keyvalue (API docs) which can be used on Objects and Maps like this:

@Component({
  selector: 'keyvalue-pipe',
  template: `<span>
    <p>Object</p>
    <div *ngFor="let item of object | keyvalue">
      {{item.key}}:{{item.value}}
    </div>
    <p>Map</p>
    <div *ngFor="let item of map | keyvalue">
      {{item.key}}:{{item.value}}
    </div>
  </span>`
})
export class KeyValuePipeComponent {
  object: {[key: number]: string} = {2: 'foo', 1: 'bar'};
  map = new Map([[2, 'foo'], [1, 'bar']]);
}
M-x
  • 658
  • 7
  • 13