What Is Angular Change Detection & Change Detection Strategies

Svetloslav Novoselski / Friday, April 29, 2022

One of Angular’s greatest strengths is its ability to easily detect and update changes in an application, while automatically rendering the updated state on the screen. To help you better understand the hype around Angular change detection, how change detection works in Angular, and the strategies that developers usually implement, I will provide some Angular change detection examples and will cover the following topics in this article:

What Is Change Detection in Angular?

Angular Change Detection is a mechanism for detecting when data changes in any component of your app and re-renders the view, so it displays the updated values or objects to end-users right away. This way, the framework makes sure the UI is synchronized with the internal state of the software – the component and the view are always in sync.

Changes occur on different occasions and derive from different events:

  • Data received from network requests or component events
  • Mouse clicks, scrolling, mouseover, keyboard navigation
  • AJAX calls
  • Use of JavaScript timer functions such as setTimeOut, SetInterval

How Does Change Detection Work in Angular?

By default, Angular performs change detection on all components (from top to bottom) whenever something triggers a change in your app - either a user event or data received from a network request, as I mentioned before. To detect and update the DOM with changed data, the framework provides its own change detector to each component. The change detector reads the binding on a template, and reflects the updated data to the view, ensuring that both the data model and the DOM are in sync.

For example, you may want to update a component binding which respectively updates the data model. The Angular change detector detects the triggered change and runs change detection to check all components in the component tree from top to bottom. This way it verifies if the corresponding model has changed. And in case of a new value, it instantly updates the DOM.

Imagine a user clicks on a Change Address Button when filling in an online form. This action automatically triggers change detection for every View in the change detection tree. The Angular change detector collects all views that are to be checked for changes and updates the value of firstname property of the user who has requested this change in the first place.

Angular Change Detection Strategies

As developers, we know that our Angular apps must match various requirements to work flawlessly, be high-performing, and deliver great UX. We must build them to be interactive, responsive and, most of all, updated, meaning the internal model state must always synchronize to the view. So, whenever we want to optimize their performance, we adopt strategies for change detection in Angular, which can update the DOM whenever the data changes.

There are two Angular change detections strategies which the framework provides:

  • Default strategy
  • OnPush strategy

Angular Default Change Detection Strategy

If Angular ChangeDetector is set to default then for any change in any model property, Angular will run change detection traversing a component tree to update the DOM. Each component has change detector which is created when the application is started.

ChangeDetectorRef class provides a few built-in methods we can use to manipulate the change detection tree:

  • markForCheck() — marks the components as it was changed, so it can be checked again for an update
  • detach() — excludes the view from the change detection tree, which means no check will be triggered until the view is re-attached again
  • detectChanges() — checks the view and its child components
  • checkNoChanges() — checks the view and its children and it will throw an error if some changes are detected
  • reattach() — reattaches a view that was previously detached so that new changes can be detected

Angular OnPush Change Detection Strategy

If Angular ChangeDetector is set to onPush then Angular will run change detector only when a new reference is being passed to the component. If observable is passed to onPush then Angular ChangeDetector must be called manually to update the DOM.

@Component({
     selector: 'app-card',
     templateUrl: './card.component.html',
     changeDetection: ChangeDetectionStrategy.OnPush,
     styleUrls: ['./card.component.scss'] 
     })
     export class CardComponent {
             …
        }
}

Benefits of onPush change detection

Unnecessary checks in child components are not performed if the parent element is updating values which are not passed as @Input() properties, providing significantly faster re-rendering of the components.

Using Change Detection With Ignite UI for Angular

Let’s create a simple example displaying a list with items for shopping using Ignite UI for Angular. Let’s have a shopping list component and an input where we can add new items to the list.

import { Component } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Component({
     selector: 'app-root',
     templateUrl: './app.component.html',
     styleUrls: ['./app.component.css']
})
export class AppComponent {
    items = new BehaviorSubject(['Apples', 'Tomatoes', 'Potatoes']);

     constructor() { }

     addNewItem(item) {
            this.items.next([...this.items, item]);
     }   
}

In the app.component.ts we will declare a BehaviorSubject with some default values and a method which is going to add a new item to the list.

<input #newItem type="text" placeholder="Add new item"> 
<button (click)="addNewItem(newItem.value)">Add Item</button> 
<shopping-items [data]="items"></shopping-items> 

We are going to create a child component shopping-items component which will display the items using igx-list component.

<h5 class="h5">Shopping List</h5>
<igx-list class="list" *ngFor="let item of shoppingItems">
    <igx-list-item class="list-item">
         <span>{{item}}</span>
     </igx-list-item>
</igx-list>

import { ChangeDetectorRef, Component, Input } from '@angular/core';
import { Observable } from 'rxjs';
@Component({
     selector: 'shopping-items',
     templateUrl: './child.component.html',
     styleUrls: ['./child.component.css']
})
export class ShoppingList {
     @Input() data: Observable<any>;
     shoppingItems: string[] = [];
     constructor(private changeDetector: ChangeDetectorRef) { }

     ngOnInit() {
         this.data.subscribe(item => {
             this.shoppingItems = [...this.shoppingItems, ...item];
             this.changeDetector.markForCheck();
         });
     }
}

If we don’t use the markForCheck() method here from ChangeDetectorRef, Angular will refuse to run change detection. That’s why we need to do it manually. With this method we tell Angular to run change detection when a particular input appeared when mutated.

Conclusion

The bigger the project, the more slowdowns it can have. Angular Change Detection is a technique which can help increase app efficiency. So, for larger projects, it would be better to use ChangeDetectionStrategy.OnPush, as it saves performance.