Reputation: 14209
This question is related to a question that has been asked on StackOverflow quite a few times.
Basically, when you do something like
@Component({
selector: 'my-app',
template: `<div>I'm {{message}} </div>`,
})
export class App {
message:string = 'loading :(';
ngAfterViewInit() {
this.updateMessage();
}
updateMessage(){
this.message = 'all done loading :)'
}
}
You get an error saying "Expression has changed after it was checked" . The reason you get this error has been explained in this post: Expression ___ has changed after it was checked
My question is, why does the following work?
@Component({
selector: 'my-app',
template: `<div>I'm {{message}} </div>`,
})
export class App {
message:string = 'loading :(';
ngAfterContentChecked() {
this.updateMessage();
}
updateMessage(){
this.message = 'all done loading :)'
}
}
Why does this not return an error, and actually returns the proper result? Why does ngAfterViewChecked work, and ngAfterViewInit not work?
Explain like I'm 5.
Upvotes: 2
Views: 2081
Reputation: 2505
The ngAfterViewInit
and ngAfterContentChecked
callbacks are Lifecycle Hooks in Angular. That is, they are called at certain, specific times during the lifecycle of your Angular Components and Directives.
The behaviour you are experiencing stems from the point in time in which Angular's Change Detection runs in relation to the point in time that each of these Lifecycle Hooks are invoked.
More specifically, the first iteration of change detection runs right after the first ngAfterContentChecked
hook but right before the call to ngAfterViewInit
.
I've created a Stackblitz Demo here (look in the console) to illustrate the flow of calls to these Lifecycle Hooks and the Change Detection runs, but I will also summarise my findings here:
By changing the value of message
inside of the ngAfterContentChecked
hook, its value will be set before the first iteration of change detection runs and spots it. This means that on subsequent change detection runs, it will have the same value as it had during the first. This is good and exactly what the Change Detector wants.
In contrast, by setting the value of message
inside of the ngAfterViewInit
hook, its value will be set after the first iteration of change detection runs. In other words, when the first iteration runs and evaluates message
, it will see that it has a value of loading :(
, directly afterwards ngAfterViewInit
is called which changes its value. Subsequent change detection runs will evaluate message
as all done loading :)
which is of course different from the previous iterations loading :(
value and thus, an ExpressionChangedAfterItHasBeenCheckedError
is thrown.
Upvotes: 5