ExpressionChangedAfterItHasBeenCheckedError in Angular — what, why and how to fix it?

ExpressionChangedAfterItHasBeenCheckedError is without a doubt my favorite error in Angular applications. Especially in my first time with Angular, I encountered this error a lot. According to GitHub, so do many others.

But when will ExpressionChangedAfterItHasBeenCheckedError be thrown? The most common reasons are:

  1. You are executing code in AfterViewInit which happens often when working with ViewChild as it is undefined until AfterViewInit is called.
  2. You are manipulating DOM directly (e.g. using jQuery). Angular cannot always detect these changes and react properly.
  3. It can also happen due to race conditions when you are calling functions inside your HTML template.

But 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) which are done in develop mode. That means that code which will work fine in develop mode will not work in production mode.

Here’s an example which would work fine in develop mode but not in production mode:

export class MyComponent {
    @ViewChild('text_node') text;

constructor() {}

ngAfterViewInit() {
// doing something with my ViewChild
}
}

How to fix ExpressionChangedAfterItHasBeenCheckedError

  1. As a quick fix, setTimeout or ChangeDetectorRef are often used to make error disappear. The latter is better since using 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.
  2. Sometimes, the error is even easier to fix: just move your code to OnInit. Unless you have to rely on ViewChild or that 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.
  3. 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 while the rest is up to you. While there is less magic involved by enabling OnPush strategy, you also get improved performance since there is less work for Angular to do (can be useful for optimizing big and complex components). On the other hand, you need to ensure yourself to let Angular pick up changes. If you do not, you will usually see UI errors (e.g. a modal not disappearing). So do not apply this over-eagerly without checking your component thoroughly.

Conclusion

Now, you should 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.