3

Here's my code

@Component({
  template: `<h1>Hello from A</h1>
  <ul>
    <li *ngFor="#letter of letters; #i = index">
      <button (click)="appendW(i)">{{letter | uppercase}}</button>
    </li>
  </ul>
  <button (click)="doSomething()">Click</button>`,
  pipes: [UpperCasePipe],
  directives: [NgFor]
})
export class AComponent {
  letters = ['a','b','c','d'];
  contructor(){

  }

  appendW(index) {
    // console.log(letter);
    setTimeout(()=>{
      this.letters[index] += "W";
    }, 1000)
  }
  ...
}

Plnkr

After setTimeout, angular checks twice for content and view. Can somebody explain this? Why does angular need to check TWICE?

Chu Son
  • 1,520
  • 3
  • 12
  • 13
  • See the `tick()` documentation in the [ApplicationRef API doc](https://angular.io/docs/ts/latest/api/core/ApplicationRef-class.html). It discusses the second round of change detection (TTL=2) that the framework does in when in dev mode... to help you find unintended side effects. – Mark Rajcok Jan 02 '16 at 20:53
  • See also Savkin's blog [Two Phases of Angular 2 Applications](http://victorsavkin.com/post/114168430846/two-phases-of-angular-2-applications), the section "How Does Angular Enforce It?" – Mark Rajcok Jan 02 '16 at 20:56

1 Answers1

11

Angular utilizes zones to know when an event is fully processed by patching some async APIs like (addEventHandler, setTimeout, ...) and then runs change detection after each event.

In dev mode Angular does an additional change detection run, just after the first one. Because there was no event in between, no change should have happened.

If the model still changed, Angular considers this to be a possible bug.

Possible causes:

  • A field, getter or function the view binds to returns a different instance each time, which is recognized as change.
    This is often with functions that return a filtered subrange of an array. This subrange should be assigned to a field and return the same cached instance unless a filter criteria has changed.
    Angular only compares identity of the previously and currently returned array and ignores whether the content of the array (or other objects) is still the same.

  • Code that was invoked by an event that was not registered within Angulars patched zone caused a model change.
    This is usually caused by 3rd-party libraries that aren't initialized fronm within Angular. Either initialize them within Angular if possible, or notify Angular about the change (Triggering Angular2 change detection manually)

In production mode Angular just checks once and ignores possible side effects.

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    "Only when nothing has changed since the previous check, Angular can be sure nothing will change anymore" -- Angular 2 can never be "sure". It runs twice in dev mode to alert you to any side effects that you need to fix. – Mark Rajcok Jan 02 '16 at 20:36
  • 2
    " In production mode Angular just checks once and ignores possible side effects" -- I'm not sure what you mean by that. I would word it a bit differently: in production mode, since the change detection graph/tree is only checked once, if there are any side effects, they may not be represented properly in the DOM (and hence in your views). They might get picked up in the next cycle, unless there is another side effect on the same piece of data. – Mark Rajcok Jan 02 '16 at 20:41