Ask Sawal

Discussion Forum
Notification Icon1
Write Answer Icon
Add Question Icon

how to use onpush change detection?

5 Answer(s) Available
Answer # 1 #

Angular implements two strategies that control change detection behavior on the level of individual components. Those strategies are defined as Default and OnPush:

Angular uses these strategies to determine whether a child component should be checked while running change detection for a parent component. A strategy defined for a component impacts all child directives since they are checked as part of checking the host component. A defined strategy cannot be overridden in runtime.

The default strategy, internally referred to as CheckAlways, implies regular automatic change detection for a component unless the view is explicitly detached. What’s known as OnPush strategy, internally referred to as CheckOnce, implies that change detection is skipped unless a component is marked as dirty. Angular implements mechanisms to automatically mark a component as dirty. When needed, a component can be marked dirty manually using markForCheck method exposed on ChangeDetectorRef.

When we define a strategy using @Component() decorator, Angular’s compiler records it in a component’s definition through the defineComponent function. For example, for the component like this:

the definition generated by the compiler looks like this:

When Angular instantiates a component, it’s using this definition to set a corresponding flag on the LView instance that represents the component’s view:

This means that all LView instances created for this component will have either CheckAlways or Dirty flag set. For the OnPush strategy the Dirty flag will be automatically unset after the first change detection pass.

The flags set on LView are checked inside the refreshView function when Angular determines whether a component should be checked:

Let’s now explore those strategies in greater detail.

Default change detection strategy means that a child component will always be checked if its parent component is checked. The only exception to that rule is that if you detach a change detector of the child component like this:

Note that I specifically highlighted the part about the parent component being checked. If a parent component isn’t checked, Angular won’t run change detection for the child component even if it uses default change detection strategy. This comes from the fact that Angular runs check for a child component as part of checking its parent.

Angular doesn’t enforce any workflows on developers for detecting when a component’s state changed, that’s why the default behavior is to always check components. An example of the enforced workflow is object immutability that’s passed through @Input bindings. This is what’s used for OnPush strategy and we’ll explore it next.

Here we have a simple hierarchy of two components:

When we click on the button, Angular runs an event handler where we update the user.name. As part of running subsequent change detection loop, the child B component is checked and the screen is updated:

While the reference to the user object hasn’t changed, it has been mutated inside but we can still see the new name rendered on the screen. That is why the default behavior is to check all components. Without the object immutability restriction in place Angular, can’t know if inputs have changed and caused an update to the component's state.

While Angular does not force object immutability on us, it gives us a mechanism to declare a component as having immutable inputs to reduce the number of times a component is checked. This mechanism comes in the form of OnPush change detection strategy and is a very common optimization technique. Internally this strategy is called CheckOnce, as it implies that change detection is skipped for a component until it’s marked as dirty, then checked once, and then skipped again. A component can be marked dirty either automatically or manually using markForCheck method.

Let’s take an example from above and declare OnPush change detection strategy for the B component:

When we run the application Angular doesn’t pick a change in a user.name anymore:

You can see that B component is still checked once during the bootstrap - it renders the initial name A. But it’s not checked during the subsequent change detection runs, so you don’t see the name changed from A to B when clicked on the button. That happens because the reference to the user object that’s passed down to B component through @Input hasn’t changed.

Before we take a look at the different ways a component can be marked as dirty, here’s the list of different scenarios that Angular uses to test OnPush behavior:

The last batch of test scenarios ensures that automatic process of marking a component dirty occurs in the following scenarios:

Let’s now explore these.

In most situations we will need to check the child component only when its inputs change. This is especially true for pure presentational components whose input comes solely through bindings.

Let’s take a previous example:

As we have seen above, when we click on the button and change the name in the callback, the new name is not updated on the screen. That’s because Angular performs shallow comparison for the input parameters and the reference to the user object hasn’t changed. Mutating an object directly doesn’t result in a new reference and won’t mark the component dirty automatically.

We have to change the reference for the user object for Angular to detect the difference in @Input bindings. If we create a new instance of user instead of mutating the existing instance, everything will work as expected:

Yep, all good:

You could easily enforce the immutability on objects with a recursive Object.freeze implementation:

So that when somebody tries to mutate the object it’ll throw the error:

Probably the best approach is to use a specialized library like immer:

This will work fine as well.

All native events, when triggered on a current component, will mark dirty all ancestors of the component up to the root component. The assumption is that an event could trigger change in the components tree. Angular doesn’t know if the parents will change or not. That is why Angular always checks every ancestor component after an event has been fired.

Imagine you have a component tree hierarchy like this of OnPush components:

If we attach an event listener inside the TodoComponent template:

Angular marks dirty all ancestor components before it runs the event handler:

Hence the hierarchy of components is marked for the check once looks like this:

During the next change detection cycle, Angular will check the entire tree of TodoComponent's ancestor components:

Note that the HeaderComponent is not checked because it is not an ancestor of the TodoComponent.

Let’s come back to the example where we changed the reference to the user object when updating the name. This enabled Angular to pick up the change and mark B component as dirty automatically. Suppose we want to update the name but don’t want to change the reference. In that case, we can mark the component as dirty manually.

For that we can inject changeDetectorRef and use its method markForCheck to indicate for Angular that this component needs to be checked:

What can we use for someMethodWhichDetectsAndUpdate? The NgDoCheck hook is a very good candidate. It's executed before Angular will run change detection for the component but during the check of the parent component. This is where we'll put the logic to compare values and manually mark component as dirty when detecting the change.

The design decision to run NgDoCheck hook even if a component is OnPush often causes confusion. But that’s intentional and there's no inconsistency if you know that it's run as part of the parent component check. Keep in mind that ngDoCheck is triggered only for top-most child component. If the component has children, and Angular doesn't check this component, ngDoCheck is not triggered for them.

So let’s introduce our custom comparison logic inside the NgDoCheck hook and mark the component dirty when we detect the change:

Remember that markForCheck neither triggers nor guarantees change detection run. See the chapter on manual control for more details.

Now, let’s make our example a bit more complex. Let’s assume our child B component takes an observable based on RxJs that emits updates asynchronously. This is similar to what you might have in NgRx based architecture:

So we receive this stream of user objects in the child B component. We need to subscribe to the stream, check if the value is updated and mark the component as dirty if needed:

The logic inside the ngOnChanges is almost exactly what the async pipe is doing:

That’s why the common approach is to delegate the subscription and comparison logic to async pipe. The only restriction is that objects must be immutable.

Here’s the implementation of the child B component that uses async pipe:

There are a bunch of test cases that test async pipe and its interaction with various types:

This test is for the use case we explored here:

The pipe subscribes to the observable inside the transform, and when the observable emits a new message, it marks the component as dirty.

[4]
Edit
Query
Report
Harashvir Kakkad
BLOCKER I
Answer # 2 #

Data flow being at the center of almost all things Angular, change detection is something worth knowing about, as it will help you trace bugs much more easily and give you an opportunity to further optimize your apps when working with a complex data set.

In this article, you will learn how Angular detects changes in its data structures and how you can make them immutable to make the most out of Angular’s change detection strategies.

When you change any of your models, Angular detects the changes and immediately updates the views. This is change detection in Angular. The purpose of this mechanism is to make sure the underlying views are always in sync with their corresponding models. This core feature of Angular is what makes the framework tick and is partly the reason why Angular is a neat choice for developing modern web apps.

A model in Angular can change as a result of any of the following scenarios:

All Angular apps are made up of a hierarchical tree of components. At runtime, Angular creates a separate change detector class for every component in the tree, which then eventually forms a hierarchy of change detectors similar to the hierarchy tree of components.

Whenever change detection is triggered, Angular walks down this tree of change detectors to determine if any of them have reported changes.

The change detection cycle is always performed once for every detected change and starts from the root change detector and goes all the way down in a sequential fashion. This sequential design choice is nice because it updates the model in a predictable way since we know component data can only come from its parent.

The change detectors provide a way to keep track of the component’s previous and current states as well as its structure in order to report changes to Angular.

If Angular gets the report from a change detector, it instructs the corresponding component to re-render and update the DOM accordingly.

In order to understand what a change detection strategy is and why it works, we must first understand the difference between value types and reference types in JavaScript. If you are already familiar with how this works, you can skip this section.

To get started, let’s review value types and reference types and their classifications.

Value Types

For simplicity, one can imagine that these types simply store their value on the stack memory (which is technically not true but it’s sufficient for this article). See the stack memory and its values in the image below for example.

Reference Types

These types are a bit more complicated as they store a reference on the stack memory, which points to their actual value on the heap memory. You can see how stack memory and heap memory work together in the example image below. We see the stack memory references the actual values of the reference type in the heap memory.

The important distinction to make between value types and reference types is that, in order to read the value of the value type, we just have to query the stack memory, but in order to read the value of a reference type, we need to first query the stack memory to get the reference and then secondly use that reference to query the heap memory to locate the value of the reference type.

As we stated earlier, Angular monitors changes on the model in order to make sure it catches all of the changes. It will check for any differences between the previous state and current state of the overall application model.

The question that Angular asks in the default change detection strategy is: Has any value in the model changed? But for a reference type, we can implement strategies so that we can ask a better question. This is where OnPush change detection strategy comes in.

The main idea behind the OnPush strategy manifests from the realization that if we treat reference types as immutable objects, we can detect if a value has changed much faster. When a reference type is immutable, this means every time it is updated, the reference on the stack memory will have to change. Now we can simply check: Has the reference (in the stack) of the reference type changed? If yes, only then check all the values (on the heap). Refer back to the previous stack heap diagrams if this is confusing.

The OnPush strategy basically asks two questions instead of one. Has the reference of the reference type changed? If yes, then have the values in heap memory changed?

For example, assume we have an immutable array with 30 elements and we want to know if there are any changes. We know that, in order for there to be any updates to the immutable array, the reference (on the stack) of it would have to have changed. This means we can initially check to see if the reference to the array is any different, which would potentially save us from doing 30 more checks (in the heap) to determine which element is different. This is called the OnPush strategy.

So, you might ask, what does it mean to treat reference types as immutable? It means we never set the property of a reference type, but instead reassign the value all together. See below:

Treating objects as mutable:

Treating objects as immutable:

Note that, in the examples above, we are “treating” reference types as immutable by convention, so in the end we are still working with mutable objects, but just “pretending” they are immutable.

So how do you implement OnPush strategy for a component? All you need to do is add the changeDetection parameter in their @Component annotation.

It is a good idea to enforce immutability if one decides to use the OnPush strategy on an Angular component. That is where Immutable.js comes in.

Immutable.js is a library created by Facebook for immutability in JavaScript. They have many immutable data structures, like List, Map, and Stack. For the purposes of this article, List and Map will be illustrated. For more reference, please check out the official documentation here.

In order to add Immutable.js to your projects, please make sure to go into your terminal and run:

Also make sure to import the data structures you are using from Immutable.js in the component where you are using it.

This is how an Immutable.js Map can be used:

And, an Array can be used:

There are a couple main arguable drawbacks of using Immutable.js.

[3]
Edit
Query
Report
Liikkanen Constantin
FAT PURIFICATION WORKER
Answer # 3 #
  • Inject ChangeDetectorRef service in the component.
  • Use markForCheck in the subscription method to instruct Angular to check the component the next time change detectors run.
  • On the ngOnDestroy() life cycle hook, unsubscribe from the observable.
[2]
Edit
Query
Report
Abhey Sanghvi
BINDERY MACHINE FEEDER OFFBEARER
Answer # 4 #

In this post we are going to cover some typical pitfalls where OnPush is giving unexpected results and how to fix those situations, we will see that OnPush is a lot simpler to use than it might look at first sight and is compatible with all sorts of component designs.

If you are also looking to learn more about the default change detection mechanism, have a look at this post How does Angular Change Detection Really Work ?

Let's have a look at a simple component that does not use yet OnPush change detection, it's a newsletter component: we will use it in a parent HomeComponent that looks like the following:

As we can see, we are passing the User data as an input. User is a simple custom type defined as the following:

As we can see on the Home component, the newsletter component is receiving as input a reference to a user object, which is currently hard-coded at the level of the Home component.

There is also a button "Change User Name", that will mutate the user data directly.

The newsletter component is currently written as a purely presentational component, that simply takes inputs and display them on the template, and emits an @Output event when the subscription occurs:

As we can see the newsletter component takes the user object as an @Input(), and displays the first name in the template.

If we test this example by clicking in the "Change User Name" button, everything will work as expected, meaning that:

This implementation with direct mutability of the user data works because we are using the Angular default change detection mechanism, which is compatible with direct object mutation.

Angular will compare the result of the expression {{user?.firstName}} before and after the click event, a change will be detected and the template will be updated with the new value.

But what if we use OnPush change detection instead?

Let's change the newsletter component so that it uses OnPush change detection:

If we now push again on the "Change Name" button, the text inside the newsletter component will remain as "Hello Alice", so our application is giving incorrect results - the view does not reflect the model anymore.

So far so good, we have an error scenario but we were actually expecting this situation - there are other scenarios below that are likely less familiar.

This situation occurs because:

If we would change the implementation of changeUserName() to create a new user instance instead of mutating the existing instance, everything would work as expected:

With this version of changeUserName() and OnPush, the text would now be "Hello Bob" after clicking the "Change User Name" button.

To avoid this issue, we simply need to either avoid mutating objects directly or use an immutability library to freeze the view model data that we pass to our components.

Actually so far this is how we would expect OnPush to work: but there is more to it than meets the eye. Even being aware of this you would still run into situations where OnPush seems like it's not working.

Is there any other way that OnPush could know that the component needs to be re-rendered? Notice that inside the newsletter component there is a button with a click handler.

If we click on the "Subscribe" button, we will see that now the template shows "Hi Bob", so the triggering of event handlers inside the component itself also causes the on push change detector to trigger, independently than if the inputs have changed or not.

So this our first indication that OnPush is more than about checking input properties.

Are there more scenarios where OnPush is also triggered?

Let's say that now the user data is not hard-coded at the level of the user component.

To make it a more realistic scenario, let's say that this data is available at a centralized UserService, that loads the data at startup time and makes the data available to any part of the application via dependency injection.

Let's have a look at what the user service looks like:

This is a simplified implementation of what a service like this would look like, normally this service would retrieve the user data from the backend using another service.

Let's break down what is going on at the level of this service:

Let's now inject this service for example in Home component, and see how to use it:

So let's break it down the changes we made here:

If we test now this application, what is the result now if we click the "Change User Name" button, will the name inside the newsletter change?

meaning that the text on the screen would now be "Hello Bob".

This is because we have emitted a new user object via the observable, so from the point of view of the newsletter component a new user object instance is still being received, so everything still works.

But now we would like to change a bit the design of our application. Let's say that instead of subscribing to the user$ observable directly at the level of the home component, we would like to pass this observable to the component tree:

As we can see, everything in the Home component remains the same but now we are passing a reference to the user$ observable to the newsletter component.

This reference will always be the same as we emit new values of this observable.

Let's now see what the newsletter component would look like:

As we can see, the component now has an input property which is an Observable, that gets subscribed to via the async pipe.

So what will happen in this case? In this case, there are no changes in the input property user$. It's still referencing the same object that just happens to be an observable.

So based on the previous error scenario, because the input property did not change we could think that the template would not be updated:

The user$ observable is being subscribed to via the async pipe, so Angular knows that the emission of values in that observable will impact the template.

And this is why with version 3, if we click on "Change User Name" the newsletter template will reflect the change and everything is still working correctly.

Let's now try other application designs and see if we run into change detection issues while using OnPush change detection.

But now we decided to do a refactoring: we now want to nest the newsletter component much deeper inside the component tree. And the tree of components contains third party libraries for which we don't necessarily have the code.

We would like to build the newsletter component so that it takes all the data that it needs from services instead of inputs, to avoid having to:

Bubbling events manually several levels up the component tree is really inconvenient and is a likely sign that the component design needs to be revisited.

Let's then re-implement the newsletter component as a deeply nested smart component:

So now this component can be injected anywhere inside the Home component sub-tree, and it will still work. In this case the home component would now look like this:

This is an example of how sometimes its better to inject services deeply in the component tree instead of passing data and bubbling events up and down the component tree, and the dependency injection system makes it really practical to do that.

There is only one problem with this approach:

This implementation manually subscribes to the user$ observable in ngOnInit will only work with the default change detection mechanism, but not with OnPush.

Does this mean that with OnPush we cannot deeply inject services in our component tree ? No, we simply need to make sure that any observables that we inject directly via constructor services are subscribed to at the template level using the async pipe:

This implementation now works great with OnPush change detection !

This is because we have subscribed to the user$ using the async pipe, so now the OnPush change detector of the newsletter can be triggered each time user$ emits a value.

But before using the async pipe, there was no way for the framework to know that values emitted by this observable where being passed the template.

Notice also a couple of new things:

As we can see, if we take some precautions in the way we build our components, OnPush will work transparently with all sorts of component designs - components that receive data directly as inputs, that have observable inputs, or components that receive data only via constructor services, etc.

An OnPush change detector gets triggered in a couple of other situations other than changes in component Input() references, it also gets triggered for example:

So if we remember to subscribe to any observables as much as possible using the async pipe at the level of the template, we get a couple of advantages:

If you would like to know about more advanced Angular Core features like change detection, we recommend checking the Angular Core Deep Dive course, where change detection is covered in much more detail.

And if you are just getting started learning Angular, have a look at the Angular for Beginners Course:

If you enjoyed this post, have also a look also at other popular posts that you might find interesting:

[1]
Edit
Query
Report
Ranveer Dhoni
CUTTING MACHINE TENDER HELPER
Answer # 5 #

Data flow being at the center of almost all things Angular, change detection is something worth knowing about, as it will help you trace bugs much more easily and give you an opportunity to further optimize your apps when working with a complex data set.

In this article, you will learn how Angular detects changes in its data structures and how you can make them immutable to make the most out of Angular’s change detection strategies.

When you change any of your models, Angular detects the changes and immediately updates the views. This is change detection in Angular. The purpose of this mechanism is to make sure the underlying views are always in sync with their corresponding models. This core feature of Angular is what makes the framework tick and is partly the reason why Angular is a neat choice for developing modern web apps.

A model in Angular can change as a result of any of the following scenarios:

All Angular apps are made up of a hierarchical tree of components. At runtime, Angular creates a separate change detector class for every component in the tree, which then eventually forms a hierarchy of change detectors similar to the hierarchy tree of components.

Whenever change detection is triggered, Angular walks down this tree of change detectors to determine if any of them have reported changes.

The change detection cycle is always performed once for every detected change and starts from the root change detector and goes all the way down in a sequential fashion. This sequential design choice is nice because it updates the model in a predictable way since we know component data can only come from its parent.

The change detectors provide a way to keep track of the component’s previous and current states as well as its structure in order to report changes to Angular.

If Angular gets the report from a change detector, it instructs the corresponding component to re-render and update the DOM accordingly.

In order to understand what a change detection strategy is and why it works, we must first understand the difference between value types and reference types in JavaScript. If you are already familiar with how this works, you can skip this section.

To get started, let’s review value types and reference types and their classifications.

Value Types

For simplicity, one can imagine that these types simply store their value on the stack memory (which is technically not true but it’s sufficient for this article). See the stack memory and its values in the image below for example.

Reference Types

These types are a bit more complicated as they store a reference on the stack memory, which points to their actual value on the heap memory. You can see how stack memory and heap memory work together in the example image below. We see the stack memory references the actual values of the reference type in the heap memory.

The important distinction to make between value types and reference types is that, in order to read the value of the value type, we just have to query the stack memory, but in order to read the value of a reference type, we need to first query the stack memory to get the reference and then secondly use that reference to query the heap memory to locate the value of the reference type.

As we stated earlier, Angular monitors changes on the model in order to make sure it catches all of the changes. It will check for any differences between the previous state and current state of the overall application model.

The question that Angular asks in the default change detection strategy is: Has any value in the model changed? But for a reference type, we can implement strategies so that we can ask a better question. This is where OnPush change detection strategy comes in.

The main idea behind the OnPush strategy manifests from the realization that if we treat reference types as immutable objects, we can detect if a value has changed much faster. When a reference type is immutable, this means every time it is updated, the reference on the stack memory will have to change. Now we can simply check: Has the reference (in the stack) of the reference type changed? If yes, only then check all the values (on the heap). Refer back to the previous stack heap diagrams if this is confusing.

The OnPush strategy basically asks two questions instead of one. Has the reference of the reference type changed? If yes, then have the values in heap memory changed?

For example, assume we have an immutable array with 30 elements and we want to know if there are any changes. We know that, in order for there to be any updates to the immutable array, the reference (on the stack) of it would have to have changed. This means we can initially check to see if the reference to the array is any different, which would potentially save us from doing 30 more checks (in the heap) to determine which element is different. This is called the OnPush strategy.

So, you might ask, what does it mean to treat reference types as immutable? It means we never set the property of a reference type, but instead reassign the value all together. See below:

Treating objects as mutable:

Treating objects as immutable:

Note that, in the examples above, we are “treating” reference types as immutable by convention, so in the end we are still working with mutable objects, but just “pretending” they are immutable.

So how do you implement OnPush strategy for a component? All you need to do is add the changeDetection parameter in their @Component annotation.

It is a good idea to enforce immutability if one decides to use the OnPush strategy on an Angular component. That is where Immutable.js comes in.

Immutable.js is a library created by Facebook for immutability in JavaScript. They have many immutable data structures, like List, Map, and Stack. For the purposes of this article, List and Map will be illustrated. For more reference, please check out the official documentation here.

In order to add Immutable.js to your projects, please make sure to go into your terminal and run:

Also make sure to import the data structures you are using from Immutable.js in the component where you are using it.

This is how an Immutable.js Map can be used:

And, an Array can be used:

There are a couple main arguable drawbacks of using Immutable.js.

As you may have noticed, it’s a bit cumbersome to use its API, and a traditional JavaScript developer may not like this. A more serious problem has to do with not being able to implement interfaces for your data model since Immutable.js doesn’t support interfaces.

You may be asking why the OnPush strategy is not the default strategy for Angular. I presume it is because Angular didn’t want to force JavaScript developers to work with immutable objects. But, that doesn’t mean you are forbidden from using it.

[0]
Edit
Query
Report