3d cartoon hands holding a phone

Unlock full course by purchasing a membership

Lesson 10

Change Detection: Signals vs OnPush vs Default

STANDARD

Change Detection and Signals

One of the great things about signals is that it will reduce a great deal of the need for us to understand precisely how change detection works in Angular.

Maybe you are starting to notice a theme in this module — the older concepts that we are covering require a great deal of explanation to try and understand the mental model and how everything fits together. The newer alternatives are usually much easier to explain and are generally just more intuitive.

Before signals, there was a lot of benefit in understanding and, to an extent, “gaming” or “optimising” your application to better suit the change detection system and improve performance (or to understand why something changed but you aren’t seeing it render on screen).

I think it will still be important to understand how change detection works with signals, but it won’t be as important as it was before. There will also be much less of these strategies for improving change detection performance.

Unfortunately, although we already have signals available in Angular, the change detection mechanisms that make full use of them are not yet stable. This will likely be coming very soon. Our strategy throughout this course will basically be to just use signals and approach change detection as if the new change detection mechanisms have already been implemented. Then, when they become available, there won’t be much if anything you will need to do to start utilising the benefits of this approach. In the mean time, change detection will work just fine with signals in our applications, the only downside is that — until the change detection update is released — it will be slightly less performant not using the OnPush change detection strategy.

We will not be implementing the old style change detection techniques (like using OnPush), but as usual we will still cover the concepts as you will likely run into Angular applications that are not using these newer approaches.

The rest of this lesson will be dedicated to understanding the old style of change detection. I am using the term “old” loosely here, because most well architected applications today use OnPush. Unless you are exclusing working with new Angular application code, it is still a concept you will need to understand for a while.

As you will see, we are about to discuss a lot of ideas and nuances that need to be kept in mind when utilising the old OnPush change detection strategy for optimising change detection. Whilst there is still plenty of depth in signals change detection to uncover to deepen your knowledge of how Angular works under the hood, the high level story of how change detection with signals works is quite simple: if a signal is updated, the signal will handle notifying Angular that a change has occurred, and Angular can update the specific thing that needs updating.

As you’re about to see — this is a refreshingly simple idea. The “downside” is that we will need to use signals for any changes we want reflected in the template using this paradigm. With the old method, as complicated and ineffecient as it is, it did allow for basically any change to be reflected no matter how it was made.

Personally, I don’t see being forced to use signals as a downside as they are fantastically powerful and rather simple to use. I am going to be using signals anyway, so the change detection improvements basically come for free.

Change Detection: OnPush vs Default

To get right to the point: Angular needs to keep track of when things in your application change. Let’s say we have a class member in the class for my component:

@Component({
  standalone: true,
  selector: 'app-home',
  template: `
    <p>{{ name }}</p>
    <button (click)="changeName()">Change name</button>
  `,
})
export class HomeComponent {
  name = 'Josh';

  changeName() {
    this.name = 'Kathy';
  }
}

The value for name is initially Josh and we are displaying that in the template. But, we have a button that triggers the changeName method when clicked which will change this value to Kathy. I encourage you to run this example for yourself, because we are going to play with this a bit.

If you click the button, you might be unsurprised to see that the value displayed in the template changes. This is what we would want to happen, but the underlying mechanisms for Angular to achieve this seemingly simple task aren’t so simple.

We could cause a change to the template in a different way — what about a setTimeout that triggers the change after 2 seconds?

@Component({
  standalone: true,
  selector: 'app-home',
  template: ` <p>{{ name }}</p> `,
})
export class HomeComponent implements OnInit {
  name = 'Josh';

  ngOnInit() {
    setTimeout(() => (this.name = 'Kathy'), 2000);
  }
}

NOTE: We are using one of Angular’s lifecycle hooks here to run some code when the component is initialised. There are other Angular lifecycle hooks like OnDestroy and AfterViewInit as well.

Or, maybe we have a setInterval changing the value every second:

@Component({
  standalone: true,
  selector: 'app-home',
  template: ` <p>{{ value }}</p> `,
})
export class HomeComponent implements OnInit {
  value = 1;

  ngOnInit() {
    setInterval(() => this.value++, 1000);
  }
}

If you run these examples, you will see that in every case the value is updated correctly. Angular detects when these changes occur and updates the template.

How does Angular detect changes?

We aren’t going to get into the precise underlying mechanisms that allow Angular to detect and respond to changes. This can become useful for performance optimisation, but it isn’t something we need to get into right now.

STANDARD
Key

Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).