ExpressionChangedAfterItHasBeenCheckedError is without a doubt my favorite error in Angular applications.
I encountered this error a lot when I first started working with Angular. According to GitHub, so do many others.
When Will ExpressionChangedAfterItHasBeenCheckedError Be Thrown?
The most common reasons are:
- You are executing code in AfterViewInit which often happens when working with ViewChild, as it is undefined until AfterViewInit is called.
- You are manipulating the DOM directly (e.g. using jQuery). Angular cannot always detect these changes and react properly.
- It can also happen due to race conditions when you are calling functions inside your HTML template.
What Is ExpressionChangedAfterItHasBeenCheckedError Trying to Warn Me About?
ExpressionChangedAfterItHasBeenCheckedError is thrown when an expression in your HTML has changed after Angular has checked it (it is a very expressive error).
This error is only thrown in develop mode and for good reason; it is often a sign that you should refactor your code, as Angular warns you that this change in your expression will not be picked up when enabling production mode!
One of the reasons why production mode is faster than develop mode, is that Angular skips some checks (e.g. change detection after AfterViewInit) that are done in develop mode. That means that code that?ll work fine in develop mode won?t work in production mode.
Here?s an example which would work fine in develop mode but not in production mode:
How To Fix ExpressionChangedAfterItHasBeenCheckedError
Fix one: let Angular know to pick up the changes
As a quick fix, setTimeout or ChangeDetectorRef are often used to make the error disappear.
The latter is better, as with ChangeDetectorRef the component view and its children are checked. On the other hand, setTimeout will cause Angular to check the whole application for changes, which is way more expensive.
Fix two: move code away from ngAfterViewInit
Sometimes, the error is even easier to fix ? just move your code to OnInit.
Unless you have to rely on ViewChild, or if some code should only run after Angular has fully initialized a component?s view, moving to OnInit will solve your issue.
This is because Angular will perform change detection after OnInit in both production and develop mode.
Fix three: use OnPush change detection
Don?t like Angular magic and how it detects changes? Just disable automatic change detection in your component and tell Angular yourself when it should detect changes.
The ChangeDetectionStrategy can be specified in a component decorator to OnPush. Now, Angular will only detect Input changes automatically, and the rest is up to you.
While there is less magic involved by enabling theOnPush strategy, you also get improved performance as there is less work for Angular to do. This can be useful for optimizing big and complex components.
On the other hand, you need to make sure you let Angular pick up changes. The prefered way to do that is using markForCheck. If you do not make Angular aware of these changes, you will usually see UI errors or inconsistencies (e.g. a modal not disappearing).
So, do not apply this over-eagerly without checking your component thoroughly.
Conclusion
You should now be able to understand when and why the infamous ExpressionChangedAfterItHasBeenCheckedError occurs.
As you can see, there are multiple ways to deal with this error. Just make sure that you are actually solving the real underlying problem, instead of working around it.