ExpressionChangedAfterItHasBeenCheckedError in Angular: What is it and How to Resolve it?

Varun, author of ExpressionChangedAfterItHasBeenCheckedError in Angular blog
Varun Omprakash
Content writer at Flexiple. Passionate about sales. Loves reading.

The infamous ExpressionChangedAfterItHasBeenCheckedError error is among the most common errors encountered in Angular applications. If you're a beginner in Angular, chances are you'd have encountered it at least once. If you're more of an Angular expert, well then you would definitely have seen it.

Although it can seem frustrating at times, this error can actually be resolved pretty easily. So in this blog, we'll cover what the ExpressionChangedAfterItHasBeenCheckedError is, why it occurs, and how to resolve it.


TABLE OF CONTENTS

  1. What is ExpressionChangedAfterItHasBeenCheckedError?
  2. Why does the ExpressionChangedAfterItHasBeenCheckedError show up?
  3. When does the ExpressionChangedAfterItHasBeenCheckedError occur?
  4. How to Resolve the ExpressionChangedAfterItHasBeenCheckedError

What is ExpressionChangedAfterItHasBeenCheckedError?


The ExpressionChangedAfterItHasBeenCheckedError error is thrown up when the binding expression changes after being checked by Angular during the change detection cycle.

However, it is displayed only in the development environment and doesn't appear when you have enabled the production environment.

This is because Angular runs the second check only in development mode to let the developer identify errors and address them. Since it takes up valuable CPU time, Angular doesn't run a second check in the production environment.

Hence, the ExpressionChangedAfterItHasBeenCheckedError isn't seen on the console window in the production environment. It is crucial to note that the error clearly exists, even though you can't see it.

It has to be said - there is no one-size-fits-all solution to the ExpressionChangedAfterItHasBeenCheckedError problem. You need to identify the root cause of the error and not try to work around it.


Why does the ExpressionChangedAfterItHasBeenCheckedError show up?


While working in a development environment, Angular takes a 'snapshot' of sorts of the parent component after the latter is set up, before proceeding down the component tree.

However, when we initialise the filter service while setting up the filter component, the parent component is sent back an update through its subscription to filterValues$. So in development mode, the earlier recorded value of the parent component doesn't match its current value when the subsequent change detection cycle is run. This disparity in values causes the ExpressionChangedAfterItHasBeenCheckedError.


When does the ExpressionChangedAfterItHasBeenCheckedError occur?


Here are some common cases wherein the ExpressionChangedAfterItHasBeenCheckedError error shows up:

1. The error occurs when you are using jQuery or a similar library to directly alter code in the DOM - these changes typically go over Angular, which causes it to react in an abnormal fashion.

2. The error can also show up when you are working with ViewChild, and execute code in AfterViewInit. As mentioned, Angular skips certain checks in AfterViewInit to save processing bandwidth in production mode.

3. This particular user on GitHub reported he encountered the ExpressionChangedAfterItHasBeenCheckedError error when he used route animation with a parent element that was conditionally hidden. However, he added that he didn't encounter the error in Angular 8.3, and started to see it only from Angular 9.


How to Resolve the ExpressionChangedAfterItHasBeenCheckedError?


Method 1. Use setTimeout


A good way to fix the ExpressionChangedAfterItHasBeenCheckedError is to make Angular aware of the fact that you have changed the code after it has completed its first check.

You can do this by using setTimeout to make the error go away. However, keep in mind that you will be using more CPU time if you use setTimeout, as it requires Angular to go through and check the whole application for changes.

export class XModule {
name = 'I am Xmodule';
@Input() text;

constructor(private parent: AppModule) {}

ngOnInit() {
    setTimeout(() => {
        this.parent.text = 'updated text';
    });
}

ngAfterViewInit() {
    setTimeout(() => {
        this.parent.name = 'updated name';
    });
}
}

Method 2. Move the component creation to ngOnInit hook


If you use the correct change detection hook to create a component that'll be changed shortly, you can bypass the error. For this, move the component creation to the ngOnInit hook.

@Component({
selector: 'course',
templateUrl: './course.module.html'
})
export class CourseModule implements AfterViewInit, OnInit {

@ViewChild(MatPaginator) paginator: MatPaginator;

ngOnInit() {
		  // load starting page
		  this.dataSource.loadLessons(...);
}

ngAfterViewInit() {
		 this.paginator.page
		     .pipe(
		         tap(() => this.dataSource.loadLessons(...))
				).subscribe();
}
}

Method 3. Deploy a second change detection cycle


You can use this.cd.detectChanges(); inside the ngAfterViewInit lifecycle hook to force another change detection cycle for the parent component before the verification phase is triggered.

However, keep in mind that triggering a change detection will make Angular run it for all child components, which means a parent property update could be triggered.


Method 4. Move your code into OnInit


Moving your code into OnInit will resolve the ExpressionChangedAfterItHasBeenCheckedError issue, as Angular performs change detection only after the OnInit phase in the development environment as well as production mode.

But it is important to ensure that you do not have any code that would run after Angular has finished initializing a component's view. You also should not use ViewChild for this method to work.


Conclusion


Hopefully, this blog gave you an understanding of what the ExpressionChangedAfterItHasBeenCheckedError is, and why and when it occurs. As mentioned previously, you need to identify and solve the underlying problem instead of attempting workarounds.

You can learn more about the error in the Angular documentation as well:

1. Video tutorial: How to debug the error

2. List of Angular errors