Why is a child component called four times on initial loading of the parent component?

433 Views Asked by At

I have a parent component and a child component. I know that change detection runs on events like HTTP request, setInterval or setTimeOut etc.

But here I don't have any of these events, and yet, when my parent component initially loads, the child component method calledChildCompo() is called four times.

Why is the change detection executed four times on initial load when I don't have events such as HTTP requests or any intervals?

AppComponent (parent)

<app-change-det></app-change-det>

ChangeDetComponent.html (child)

{{ calledChildCompo() }}

ChangeDetComponent.ts (child)

@Component({
  selector: 'app-change-det',
  templateUrl: './change-det.component.html',
  styleUrls: ['./change-det.component.scss']
})
export class ChangeDetComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

  calledChildCompo() {
    console.log('child compo is called');
  }

}
2

There are 2 best solutions below

3
On

Have a look at the below Demo with no child component or parent component Demo

What I have is simply

TS


  ngOnInit() {
    console.log('Init')
  }
  testFunction() {
    console.log('TEST')
  }

HTML

{{ testFunction() }}

If you look at the console You will see 4 logs with the word TEST but only 1 'init'. It simply a function working as expected, function reevaluates severally.

It is important to note that this reevaluation may cause your application to become slow. it is a bad idea to include functions in the html. Functions reevaluate for any slight change

Explanation

Angular’s Digest Cycle

What you are seeing is the digest cycle at work. The digest cycle is how Angular’s auto-update magic works – it’s the reason that typing into an input box automatically updates anything that refers to its value.

When the digest cycle runs, it effectively redraws everything that might have changed on the page.

Angular uses some tricks to find “everything that might have changed”, and the main technique is watchers. These watchers are created automatically when you use directives like ng-if and ng-class, and when you use bindings like {{ yourBindingHere }}.

Each one of those things registers a watcher. When Angular’s digest cycle runs, every watcher is asked to update its state. In the case of ng-class, it will re-run the function bound to it, to see if anything needs to change. This is why your controller function runs multiple times, and it’ll run again each time something changes on the page.
Source Controller Function Is Executed Multiple Times

2
On

If you start your Angular app it will do an initial change detection cycle so that it knows all bound values and can render the page in the browser. For some reason, it actually executes two CD cycles on startup. (You could check it in the Angular source code, but I do not know the reason why.)

I suspect that you checked the number of CD cycles by running your app in dev mode. This explains why the number is 2*2 cycles. In dev mode, after each CD cycle there is an additional "check" cycle run, to check if any bound value changed during the actual change detection. If this is the case, the infamous ExpressionChangedAfterItHasBeenChecked error is thrown. This is to warn you that your model and view might be out of sync after the CD cycle. In prod mode, the additional cycle is skipped to have a better performance.