What causes Angular2 to detect both reference changes and primitive changes even when the OnPush flag is enabled?

Take a look at this code snippet

import {Component, OnInit, Input, OnChanges, DoCheck, ChangeDetectionStrategy} from 'angular2/core'

@Component({
  selector: 'child1',
  template: `
    <div>reference change for entire object: {{my_obj1.name}}</div>
    <div>reassign primitive in property of object: {{my_obj2.name}}</div>
    <div>update primitive in property of object: {{my_obj2.num}}</div>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class Child1 {

  @Input()
  my_obj1: Object = {'name': ''};

  @Input()
  my_obj2: Object = {'name': '', 'num': 0};

  ngDoCheck() {
    console.log('check from child1');
    console.log(this.my_obj1);
    console.log(this.my_obj2);
  }
}

@Component({
  selector: 'parent',
  template: `
    <div>
      <child1
        [my_obj1]="my_obj1"
        [my_obj2]="my_obj2"
      >
      </child1>
      <button (click)="change_obj1()">
        Change obj1
      </button>

    </div>
    `,
  directives: [Child1]
})
export class App {

  my_obj1: Object = {'name': 'name1'};
  my_obj2: Object = {'name': 'name2', 'num': 0};

  change_obj1() {
    this.my_obj1 = {'name': 'change1'}
    this.my_obj2['name'] = 'change2';
    this.my_obj2['num'] += 1;
  }
}

After conducting an experiment, I have come to understand the current change detection strategy in Angular2. Can someone confirm if my understanding is accurate?

  1. By default, Angular2 checks for value equality during change detection. Without ChangeDetectionStrategy.OnPush, every watched variable in the component tree undergoes a check for value equality. If there is a mismatch, that specific component will be re-rendered, otherwise it will not.

  2. When implementing ChangeDetectionStrategy.OnPush in a component, the behavior changes as follows:

    i. If there is a reference change within the component, it triggers a re-render and initiates change detection in child components based on the specific algorithm defined by ChangeDetectionStrategy.OnPush.

    ii. If there is no reference change within the component, no re-render occurs, and change detection is skipped in child components, regardless of the presence of ChangeDetectionStrategy.OnPush.

Is this interpretation correct?

Answer №1

I made some adjustments to your plunker: check it out here

Since primitive values are immutable, there is no difference between reassigning and updating - the primitive gets the new immutable value, so I decided to remove the "updating" code. Additionally, splitting out assigning a new object reference (which triggers change detection) from assigning a new primitive value (which does not trigger change detection) can be quite helpful.

If you test my Plunker example, we can make these observations:

  1. Changing an input property that is a reference type on an OnPush component will result in an update of the component's view. The template bindings are checked for changes, and child components are also checked unless they are using OnPush.
  2. Modifying a primitive property within a reference type on an OnPush component will not trigger an update of the component's view. The template bindings are not checked for changes, and child components are also unaffected, regardless of their usage of OnPush.
  3. ngDoCheck() is always invoked on the first OnPush component, regardless of whether the template bindings are checked for changes or not. This behavior may seem peculiar, but it occurs nonetheless. Therefore, the invocation of ngDoCheck() does not necessarily indicate that template bindings have been assessed for alterations.

It's worth noting that when a change is detected in a template binding, only that specific alteration is passed down to a child component or the corresponding DOM element. If the binding modification leads to a change in the DOM, only that particular DOM data will be updated without rerendering the entire component. This approach differs from certain other frameworks where any alteration prompts a complete rerendering of the template, making Angular's handling of updates more efficient.

Answer №2

If you're looking for a detailed explanation, check out this post:

In essence, Angular2 needs to be cautious and compare values thoroughly, conducting a 'deep check' of referenced objects.

When using ChangeDetectionStrategy.OnPush, components will only update if the input object references have changed.

This is why immutable objects are often favored—the component points to a new object when updates are made, making it easier for Angular to identify which components require updating.

Efficient behavior can also be achieved through observables by utilizing

ChangeDetectorRef.markForCheck();
.

You can learn more about this concept here:

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can you detect when a user clicks outside of a bootstrap modal dialog in Angular?

Is there a way to detect when a user clicks outside of a Bootstrap modal dialog? <!-- EXPANDED MODAL --> <div class="modal fade" id="itinerary" tabindex="-1" role="dialog" aria-labelledby="modal-large-label"> <div class="modal-dial ...

In Node.js, when accessing a Firebase snapshot, it may return a

Currently, I am utilizing Firebase functions to execute the code for my Flutter application. This code is responsible for sending push notifications to my app. However, I am encountering an issue where I receive a null value at snap.val(). Take a look at h ...

Angular6 : PrimeNg datatable: the nova-light theme failing to activate

I'm currently working on an Angular 6 app that is equipped with the latest version of PrimeNG (6.1.4) and I am using a simple datatable component. My goal is to apply the nova-light theme to my datatable, but unfortunately, it is not being applied cor ...

Is there a way to access the original query string without it being automatically altered by the browser?

I'm currently encountering an issue with query strings. When I send an activation link via email, the link contains a query string including a user activation token. Here's an example of the link: http://localhost:3000/#/activation?activation_cod ...

Utilizing Typescript: Ensuring an array includes only specified values from an enum through strict enforcement

In my Angular application, I have an HTTP service that returns the allowed accesses for a specific user. The response structure is as shown below:- { "accessId": 4209318492034, "folderPath": "data/sample_folder/", ...

Retrieve an item from the Ionic Firebase database

My current challenge is retrieving data from the Firebase database. user-service.ts getProfile(){ try {; return this.afDatabse.object(`profile/${this.afAuth.auth.currentUser.uid}`); } catch (e) { console.log(e); } } c ...

Encountering an Issue Executing Selenium Test on jQuery v2.0.2 and Play Framework

While I may not be a selenium expert, it seems that I've stumbled upon a bug when trying to utilize jQuery v2.0.2 with my Play Framework 2.2.1 application instead of the default jQuery v.1.9.0. Whenever I run "play test", I encounter the following err ...

Utilizing the spread syntax for elimination

I want to remove a key. Check this out console.log(state); When I do, I get {1: {here is next object}}, next const { 1: deletedValue, ...newState } = state; console.log(newState); console.log(state); But then I end up with {1: {here is next object}} ...

Using Functional Programming with Node.js: A guide to waiting for a function to complete

As a newcomer to Node.js, I am satisfied with the syntax of JavaScript as I have utilized it for constructing web interfaces. With substantial experience in Object-Oriented Programming from Java and C#, along with an understanding of functional programming ...

Obtaining network information in Angular

Greetings! I am currently working on my angular application and I need to obtain information about the network. Specifically, I want to know if there is a network connection available and which WiFi network it is connected to. Although I can monitor the ...

Function that activates traffic lights

Currently, I'm encountering errors while working on this project in Notepad. Can you help me figure out what's wrong with my code? I'm attempting to create an onload traffic light using an object array. The requirement is to implement this f ...

The retrieval process is unable to receive a response from the server

Question: I am encountering an issue with the fetch API in the client-side code. Here is the snippet of the code: window.fetch('/signup', { method: 'post', headers: { 'Content-Type': 'application/x-www-form-urlen ...

Using jQuery Ajax to send data and retrieve responses in the Codeigniter framework

I am struggling with passing values in CodeIgniter and I need some guidance. Could you provide an example code snippet using CodeIgniter to send a value from a view to a controller using Ajax and jQuery, and then display the result on the same page? In my ...

Issues with card flip functionality in Firefox

I designed this animation specifically for my website to create a unique effect. The animation involves translating on the Z-axis, making it appear as though the object is getting smaller, flipping to reveal the back of the card, and then translating back. ...

What is the best way to provide a parameter to the query function in an Angular service class?

This snippet of code was generated by jHipster. invoice.component.ts @Component({ selector: 'jhi-invoice', templateUrl: './invoice.component.html' }) export class InvoiceComponent implements OnInit, OnDestroy { loadAll() ...

Trying out the results of angular services

Seeking assistance in understanding the current situation: I believe a simple tour of heroes app would be helpful in clarifying, I am looking to set up some tests using Jest to verify if the behavior of a service remains consistent over time. This is ho ...

Parsing JSON data using a regular expression

Within my JavaScript file lies a plethora of object literals: // lots of irrelevant code oneParticularFunction({ key1: "string value", key2: 12345, key3: "strings which may contain ({ arbitrary characters })" }); // more irrelevant code My ta ...

Angular's custom reactive form validator fails to function as intended

Struggling to incorporate a customized angular validator to check for date ranges. The validator is functioning correctly and throwing a validation error. However, the issue lies in the fact that nothing is being displayed on the client side - there are n ...

What strategies can I use to successfully navigate through this component?

I'm looking to display "favorite" items within my favorites component. However, I'm facing a challenge since I can't directly pass the postList component to the favorites component. Essentially, I aim to showcase these favorite items on ano ...

Neglecting to Execute Success Function After Retrieving Data from PageMethods Using Multiple Parameters in C#

I attempted to trigger my OnSuccess function, but it did not execute on the server. This is my code: function Get_Data(option , text){ //returns 'data', 'data', --not call OnSuccess-- PageMethods.BindSeries(option,text,OnSuccess); ...