Why is both reference change and primitive change catch by Angular2 during change detection even with OnPush flag set?

Consider the following code

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;
  }
}

From the experiment I made, here is my understanding of the current Angular2 change detection strategy, can someone verify it if its true?

  1. Angular2 by default checks for value equality when doing change detection. If there are no ChangeDetectionStrategy.OnPush, every watched variable in component tree is checked for value equality. If value equality is false, that specific component will be rerender, and if value equality if true, that specific component will not be rerender.

  2. If you add ChangeDetectionStrategy.OnPush to a component. The behavior changes as follows

    i. If variable inside the component have reference change, the component is rerendered, and child component is checked for change detection (its specific change detection algorithm value/reference check depends on ChangeDetectionStrategy.OnPush)

    ii. If variable inside the component don’t have reference change, the component is not rerendered, and child component is not checked for change detection, regardless of presence of ChangeDetectionStrategy.OnPush

Is this the correct interpretation?

2
Leave a Reply

avatar
2 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Jason Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Jason
Guest

I reworked your plunker a bit: new plunker Since primitive values are immutable, there is no difference between reassigning and updating – the primitive gets the new immutable value, so I removed the “updating” code. Also, it is very helpful to split out assigning a new object reference (which does trigger change detection) and assigning a new primitive value (which does not trigger change detection). So I did that also. If you run my Plunker we can make the following observations: changing an input property that is a reference type on an OnPush component will update the component’s view. The… Read more »

Jason
Guest

This post explains it in detail pretty well:

http://victorsavkin.com/post/133936129316/angular-immutability-and-encapsulation

In short you’re assumptions are correct. Angular2 must be conservative and check for value equality, i.e. it must do a ‘deep check’ of the objects referenced.

With ChangeDetectionStrategy.OnPush, components will only be updated if the references to their input objects have changed.

Thus is why immutable objects can be preferred data structures–if we must update an object, the component is now referencing a new object. And it is therefore easy for angular to know which components must be updated.

Performant behavior can also be achieved with observables, through the ChangeDetectorRef.markForCheck(); method.

This is explained here:

http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html