Change detection strategy in Angular

Diario del capitán, fecha estelar d309.y38/AB

After having worked in dozens of Angular projects as a developer, I have seen multiple occasions in which the default configuration of Angular is not always the most recommendable.

Today, I am going to talk about the detection strategy in Angular and how to change it to improve performance and to adapt it to your project requirements.

Photo of lights in traffic in a timelapse

By default, Angular components use ChangeDetectionStrategy.Default strategy. This means that every time something changes in your application, Angular will check every property of the component to verify if the view is up-to-date.

This is very useful because we don't have to worry about components not displaying its latest state in the view when a property changes, even if the change is deep inside an object.

The downside of ChangeDetectionStrategy.Default is its performance. When the application grows, Angular will need to check more and more components and their properties, consequently impacting the user experience.

To ease this potential problem we can change the strategy for each component:

import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'my-component',
  templateUrl: './my.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent {
...
}

The above code sets the change detection strategy for a given component to OnPush.

The OnPush strategy will trigger the Change Detector only when:

  • An Input reference changes. (I said reference, very important)
  • If a component event handler gets triggered.
  • When an observable emits a new value and we are using the pipe async in the template to observe.

If you need to run change detector once inside a component with ChangeDetectionStrategy.OnPush you can do it manually injecting the ChangeDetectorService and markForCheck method:

import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'my-component',
  templateUrl: './my.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent {
    constructor(private changeDetectorRef: ChangeDetectorRef){}

    performSomething() {
        // change the state of the component
        ....

       this.changeDetectorRef.markForCheck();
    }
}

Sometimes, this is not enough and you want to take control of the Change Detector. Performance-wise - it is the best option -, you can detach the Change Detector completely to reattach it or to call the Change Detector manually later.

import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'my-component',
  templateUrl: './my.component.html'
})
export class MyComponent {
    constructor(private changeDetectorRef: ChangeDetectorRef){
       // detattach change detector for this component, any change will be ignored
       this.changeDetectorRef.detach();
    }

    performSomething() {
        // change the state of the component
        ....

       this.changeDetectorRef.detectChanges();
    }

    enableDetector() {
         this.changeDetectorRef.reattach();
    }
 }

Further reading

If you're interested in learning more about this configuration tweak, I'd strongly recommend reading the following sources:

Thanks for reading so far! Hope you found this useful!

David Garmendia

David Garmendia

Nuestro especialista en JavaScript (Angular, Node.js, React y Ionic) es originario de Asturias. Se mudó a Barcelona cuando lo fichamos pero no encontró una oficina, porque nuestra empresa es 100% remota.

comments powered by Disqus

Estás a un paso de conocer a tu mejor socio.

Hablemos