Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

angular - Updating boolean in AfterViewInit causes "Expression has changed after it was checked"

I have a simple alert component which I'm creating dynamically in the view. Since it's created dynamically I've set an option to automatically display the alert after it has been initialised.

Although it's working I'd like to understand why I have to manually trigger the change detection in this particular case.

Code:

export class OverlayMessageComponent implements AfterViewInit {
    ...

    ngAfterViewInit() {
        if(this.autoShow) {
            this.show();
        }
        this.changeDetector.detectChanges();
    }

    ...
}

Full Sample: https://plnkr.co/edit/8NvfhDvLVBd71I7DR0kW

I had to add this.changeDetector.detectChanges(); as I was getting the following error:

EXCEPTION: Expression has changed after it was checked.

I was under the impression that using AfterViewInit helps avoiding the issue, but I think I'm assuming wrong. Is there a way to structure the code better to avoid this error?

I'd like to understand better why this error is returned. I've seen this error a few times before, and I know that some say that with a setTimeout() or enableProdMode() does solve the issue, but to me it seems a hacky workaround when the framework itself is notifying you that there's a problem.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I'd like to understand better why this error is returned

The AfterViewInit and AfterViewChecked lifecycle hooks are triggered after change detection has completed and the view has been built. So any code that runs at this point should not update the view, or your app and its view will fall out of sync. Take a look at the docs

Angular's unidirectional data flow rule forbids updates to the view after it has been composed. Both of these hooks fire after the component's view has been composed.

Angular throws an error if the hook updates the component's data-bound comment property immediately.

As a result, you must either manually trigger change detection -- which is an expensive operation because Angular has to go through the whole App again -- or make the change asynchronously so that the view will be updated at the next change detection step, with something such as:

if(this.autoShow) { setTimeout(()=>this.show,0)}

Or more simply, if you don't need to grab a handle of something in the view, you can run your code in ngOnInit() or a little later in ngAfterContentInit(). Because these run before the view is composed, you can make changes that affect the view without trouble.

Docs: lifecycle hooks order


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...