Change Detection in Angular

Kaan Kırcaklı
Mercury Business Services
4 min readMar 4, 2024

Change detection is a mechanism that enables Angular applications to keep the user interface updated so it can correctly display the current state of the application. In this article, we will explore Angular’s change detection mechanism, including Zone.js , Default change detection, OnPush strategy and Local Change detection.

For demonstration purpose I created a simple visual representation of a component tree.

Our Example Component Tree

Zone.js

Zone.js is a library that notifies Angular of changes in the application state whenever asynchronous tasks complete or when DOM events are handled. This process involves “monkey patching,” where Zone.js redefines various asynchronous APIs to intercept calls and invoke Angular’s change detection.

Default Change Detection

For Angular’s default change detection the flow is something like this , For example we triggered a click event from “Component F”. Zone.js notifies Angular. Basically it tells Angular that an event is triggered and a value of a component might be changed so run change detection cycle to see if something is changed if so update the UI. Then Angular traverses our component tree from top to bottom and runs change detections for all components.

Default Behaviour

As you can see Angular runs the change detection for all of the components. So there is a lot of unnecessary change detections.

OnPush Change Detection

The OnPush change detection strategy provides a way to optimize change detection by stopping the default behavior. When a component uses the OnPush strategy, change detection stops, and Angular checks if the component is marked as dirty before proceeding.

OnPush Strategy (every component is using OnPush strategy)

As you can see only the components which marked as dirty are checked for changes. This will better optimize our change detection process.

@Component({
...
changeDetection: ChangeDetectionStrategy.OnPush,
}) // You can change the change detection to OnPush like this

However, remember that when using OnPush change detection strategy, Angular assesses changes in input bindings by comparing their values based on reference.

@Component({
selector: 'app-books',
template: `
<div *ngFor="let book of bookList">
{{book.title}}
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class BookListComponent {
@Input() bookList: any;

}
@Component({
template: `
<button (click)="add()">Add</button>
<app-books [bookList]="bookList"></app-books>
`
})
export class AppComponent {
bookList = [{ title: 'Lord of The Rings' }, { title: 'Star Wars' }];

changeTitle() {
this.bookList[0].title = 'Papillon';
} //this change will not be reflected because with OnPush strategy Angular
//compares values with reference and reference is still the same.

changeTitle() {
const newBookList = [...this.bookList];
newBookList[0].title = 'Papillon';
this.books = newBookList
}// you need to do something like this to make it work
}

Marking Components as Dirty

To reflect changes to the DOM when using OnPush, components must be marked as dirty. This can be achieved through various ways, including:

  • Manually using ChangeDetectionRef and calling markForCheck method.
  • DOM events.
  • Async pipe.
  • Property binding.
  • Signals.

When we mark as dirty ancestors automatically marked as dirty as well because this components ancestors might have OnPush change detection strategy and if we don’t mark ancestors as dirty it won’t check its child.

Local Change Detection

Angular 17 introduces local change detection for signals. Now, when a signal changes in Angular 17, the component marks itself as dirty, but this change does not automatically cause the ancestor components to be marked as dirty. Essentially, we can mark individual components as dirty and their ancestor components can be marked as traversal, but it requires using the OnPush strategy in conjunction with signals. The future of signals is trending towards applications without Zone.js, incorporating signal components. With additional enhancements in the future, we may achieve zoneless applications with signal components, enabling us to precisely pinpoint and update components directly.

Conclusion

By grasping the different approaches on change detection, developers can optimize their applications and enhance the overall application performance. As Angular continues to evolve, staying informed about updates and best practices ensures developers to leverage the latest features and improvements in change detection mechanisms.

--

--