One of the most common Angular errors developers face is the dreaded:
ExpressionChangedAfterItHasBeenCheckedError
This error occurs when Angular detects that a binding value has changed after change detection has already run. It typically happens in components that update values during the wrong lifecycle hook or due to async operations.
This guide explains what causes the error, how to fix it, and how to prevent it in your Angular project.
1. What Causes the Error?
Angular runs a change detection cycle to check if data-bound values remain stable.
This error occurs when:
- A property changes after the initial change detection
- You update values in ngAfterViewInit or ngAfterViewChecked
- Async events (setTimeout, subscriptions) modify the model at the wrong time
- Child component inputs are updated too late
- Change detection strategy conflicts with the update timing
This is Angular’s safety check to prevent unpredictable UI changes.
2. Most Common Example
export class DemoComponent implements AfterViewInit {
@Input() title!: string;
ngAfterViewInit() {
this.title = 'Updated Title'; // ❌ Causes ExpressionChangedAfterCheckedError
}
}
Angular already checked title, and changing it afterward triggers the error.
3. How To Fix It
✔ Fix 1: Move Updates to ngOnInit
If possible, update values earlier:
ngOnInit() {
this.title = 'Updated Title'; // ✅ No error
}
✔ Fix 2: Use ChangeDetectorRef
If you must update in AfterViewInit:
constructor(private cd: ChangeDetectorRef) {}
ngAfterViewInit() {
this.title = 'Updated Title';
this.cd.detectChanges(); // ✅ Forces Angular to re-check
}
✔ Fix 3: Wrap Async Updates in setTimeout
This defers changes to the next macro-task:
ngAfterViewInit() {
setTimeout(() => {
this.title = 'New Title';
});
}
✔ Fix 4: Use markForCheck with OnPush Strategy
If using OnPush:
constructor(private cd: ChangeDetectorRef) {}
updateValue() {
this.value = 'Updated';
this.cd.markForCheck();
}
4. How To Prevent This Error
- Avoid mutating values inside
ngAfterViewInitorngAfterViewChecked - Keep component input updates inside lifecycle hooks like
ngOnInit - Simplify change detection using
OnPush - Use immutable patterns to avoid accidental value changes
- Ensure async updates aren’t triggered in the middle of rendering
- Do not mutate objects used directly in templates
These practices help maintain stable and predictable component rendering.
5. Final Checklist
Before marking the error as resolved, check:
✔ No late property mutations in view lifecycle hooks
✔ No async updates interfering with change detection
✔ Input bindings are stable
✔ No direct DOM manipulations affecting values
✔ Proper use of ChangeDetectorRef when required
Following these steps guarantees a stable Angular app without lifecycle-related errors.
Citations
Internal: https://savanka.com/category/savanka-helps/
External: http://angular.dev/