How to Fix Angular ExpressionChangedAfterItHasBeenCheckedError
In this tutorial, you'll learn about How to Fix Angular ExpressionChangedAfterItHasBeenCheckedError. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
The Problem
Angular throws ExpressionChangedAfterItHasBeenCheckedError when a property changes after Angular has finished checking the view in development mode, causing a discrepancy between the current and previous value.
Quick Fix
Step 1: Move state initialization to ngOnInit
Updating shared state in child component constructors can trigger this:
@Component({
selector: 'app-child',
template: '{{ value }}'
})
export class ChildComponent {
@Input() value: string;
constructor(private service: DataService) {
this.service.data$.subscribe(data => this.value = data);
}
}
Move the subscription to ngOnInit:
export class ChildComponent implements OnInit {
@Input() value: string;
constructor(private service: DataService) {}
ngOnInit() {
this.service.data$.subscribe(data => this.value = data);
}
}
Step 2: Use setTimeout for async updates
Wrap the change in setTimeout to run after change detection:
export class AppComponent {
loading = true;
constructor(private service: DataService) {
this.service.load().then(() => {
this.loading = false;
});
}
}
Delay the change to after change detection:
ngAfterViewInit() {
setTimeout(() => {
this.service.load().then(() => {
this.loading = false;
});
});
}
Step 3: Use ChangeDetectionStrategy.OnPush
OnPush reduces the likelihood of expression changes:
@Component({
selector: 'app-example',
template: '{{ data }}',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExampleComponent {
@Input() data: string;
}
With OnPush, the component only checks for changes when inputs change or events fire.
Step 4: Use detectChanges from ChangeDetectorRef
Manually trigger change detection after the change:
export class AppComponent implements AfterViewInit {
constructor(private cd: ChangeDetectorRef) {}
ngAfterViewInit() {
this.service.load().then(data => {
this.data = data;
this.cd.detectChanges();
});
}
}
Step 5: Split the component when the tree is complex
Deep nested components triggering parent updates cause this error. Refactor to pass data down rather than updating parent state from children.
Prevention
- Initialize data in
ngOnInitrather than constructors. - Use
setTimeoutto defer updates past the current change detection cycle. - Use
ChangeDetectionStrategy.OnPushfor predictable change detection. - Avoid having child components modify parent state during view checking.
- Use
detectChanges()explicitly when updating afterAfterViewInit.
Common Mistakes with expression changed
- Non-exhaustive pattern matches that compile with warnings then crash at runtime
- Misunderstanding that
Stringis[Char]with poor performance for large text operations - Using
foldlinstead offoldl'causing stack overflow on large lists
These mistakes appear frequently in real-world Angular code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro