I have a small TypeScript code snippet as below:
ngAfterViewChecked(){
console.log("ngAfterViewChecked 1");
setTimeout(() => {
console.log("ngAfterViewChecked 2");
}, 1000);
}
Function setTimeOut()
is supposed to get the lambda function called after 1 second and then stop. However, the hook ngAfterViewChecked() is called continuously (excerpt from Chrome Developer Tool Console):
00:36:50.827 home.component.ts:53 ngAfterViewChecked 1
00:36:51.842 home.component.ts:55 ngAfterViewChecked 2
00:36:51.843 home.component.ts:53 ngAfterViewChecked 1
00:36:52.843 home.component.ts:55 ngAfterViewChecked 2
00:36:52.844 home.component.ts:53 ngAfterViewChecked 1
00:36:53.845 home.component.ts:55 ngAfterViewChecked 2
00:36:53.846 home.component.ts:53 ngAfterViewChecked 1
00:36:54.848 home.component.ts:55 ngAfterViewChecked 2
...
Without the setTimeOut()
, function ngAfterViewChecked()
is called once. This issue occurs also with ngDoCheck()
, ngAfterContentChecked()
.
The same code body, with or without setTimeOut()
, declared in constructor()
, ngOnInit()
, ngAfterContentInit()
, ngAfterViewInit()
, gets called once as expected.
Both Angular 5 & 6 have this issue (lower versions haven't been tested). They were installed separately in different machines.
Angular CLI: 6.0.8
Node: 8.11.3
OS: win32 x64
Angular: 6.0.9
Angular CLI: 1.7.4
Node: 8.11.1
OS: win32 x64
Angular: 5.2.10
Windows 8.1 x64.
The hooks constructor()
, ngOnInit()
, ngAfterContentInit()
, ngAfterViewInit()
are called once in the entire Lifecycle of a Component, regardless of how its content evolves through out its life. So this issue reasonably doesn't happen in these hooks.
With ngDoCheck()
, ngAfterContentChecked()
and ngAfterViewChecked()
, they get called when Angular detects changes. But as showed in the lambda function body, only simple console.log()
is used. I think Angular might intercept the setTimeOut()
call and blindly believes that there could have been some changes, so it starts the Change Detection process, which leads to what we have seen: calls chained infinitely.
Is this a bug or a feature?
Feature - Angular's change detection runs after asynchronous operations complete (like setTimeout) - so the setTimeout itself it causing ngAfterViewChecked
to run, and vice versa.
You can run things outside of Angular's Zone if you don't want that to happen, i.e.
ngAfterViewChecked(){
console.log("ngAfterViewChecked 1");
this.ngZone.runOutsideAngular(() => {
setTimeout(() => {
console.log("ngAfterViewChecked 2");
}, 1000);
});
}
You can inject NgZone in your constructor, i.e. private ngZone: NgZone
. Check out the relationship between Angular and zone.js for more info.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With