0

I am calling a function from inside an angular template (interpolation), strangely the function is getting invoked four times !!

I do know how change detection works in angular, as I understood change-detection process kickstarts if binding value gets updated.

In this scenario, I am not binding / changing any thing as such..

var i = 0;

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h1>{{ parentCounter() }}</h1>
    </div>
  `,
})
export class App {
  name:string;
  constructor() {
    
  }
  
  parentCounter(){
    alert(`${++i} called`);
    return 5;
  }
}

Ref: https://plnkr.co/edit/pta0s0nzcsLdTsjCtb3D?p=preview

Note: Template got compiled four times before the async event

Template got compiled four times before the async event

kalki
  • 465
  • 7
  • 14
  • https://stackoverflow.com/questions/45412199/angular-change-detection-runs-eight-times-instead-four/45412670#45412670 – yurzui Nov 19 '17 at 07:34
  • https://stackoverflow.com/questions/41187667/why-angular2-executes-methods-several-times/41191641#41191641 – yurzui Nov 19 '17 at 07:35

2 Answers2

1

If you bind to functions in the view like

<h1>{{ parentCounter() }}</h1>

then Angular calls this function every time change detection is run.

If this function returns a new object every time it is called, you'll even get an exception in development mode.

Expression has changed since it was last checked

It is better to assign the result of the call to a field and bind to that field instead.

var i = 0;

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h1>{{ counter }}</h1>
    </div>
  `,
})
export class App {
  name:string;
  counter:number;
  constructor() {
    this.counter = this.parentCounter();
  }

  parentCounter(){
    alert(`${++i} called`);
    return 5;
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    I am aware of that.. But I want to know why change detection happen four times ? – kalki Nov 17 '17 at 11:57
  • 1
    In development mode Angular runs change detection twice every time to check for the bug in mentioned in my answer (Expression has changed ...). Therefore Angular runs change detection twice when your application is started. I don't know exactly why. Afterwards it runs once (double takes) when an event happens. See the console log of https://stackblitz.com/edit/angular-gn8gga – Günter Zöchbauer Nov 17 '17 at 12:06
  • And when Gunter says events, he means every browser event. Every recordable mouse movement or keyboard stroke, etc. triggers change detection. – jcairney Oct 02 '19 at 19:46
  • Only events that an Angular component or a decendant binds to. I haven't seen other events cause change detection to run. – Günter Zöchbauer Oct 03 '19 at 03:46
1

enter image description here

enter image description here

As stated in the previous answer comments there are two calls each time as you can see in the pictures to check that the value hasn't changed due to subsequent calls (idempotent test). The first set of 2 calls is initiated from the bootstrap/initial parsing of the page, the second pair of calls is triggered as the result of the readystatechange event firing off and the automatic zone/async handler triggering a view update.


Also just to add this is really going to be insignificant. Performance issues arise from pages that have components typically in repeaters with tons of data bindings leading to pages with 10s of thousands of data bindings (and then people complain that it is slow :) ) Check out the timeline and chrome profiling tools they are invaluable, also to dig into this myself I used a debugger keyword and the call stack to see what was going on in general.

shaunhusain
  • 19,630
  • 4
  • 38
  • 51
  • Thanks for the answer !! I just tried it again by keeping the debugger points and found that template being evaluated four times (part of change detection) before the readyStateChange event from zone js.. Uploaded an image regarding this, pls check it.. Correct me if I am wrong. – kalki Nov 19 '17 at 07:22