Search code examples
angularangular2-changedetection

changeDetection: ChangeDetectionStrategy.OnPush doesn't seem to be working?


https://stackblitz.com/edit/angular-xpamld

Question: Can someone help me understand why my prototype's changeDetection: ChangeDetectionStrategy.OnPush still allows me to update the inner value name? If this is not what ChangeDetectionStrategy.OnPush suppose to prevent, what should it be doing?

app.component.ts:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent  {
  public name = 'Angular 5';
  public changeName() {
    this.name = 'Outer';
  }
}

app.component.html:

<hello name="{{ name }}"></hello>
<button (click)="changeName()">Outter Change</button>
<p>{{name}}-- outer</p>
<p>
  Start editing to see some magic happen :)
</p>

hello.component.ts:

@Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1> <button (click)="changeName()">inner Change</button>`,
  styles: [`h1 { font-family: Lato; }`],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HelloComponent  {
  @Input() name: string;


  public changeName() {
    this.name = 'Inner';
  }
}

Solution

  • Because primitive datatype is immutable - if you change it, its reference also changes, so ChangeDetectorRefof your component knows it must detect changes (because OnPush looks for references changes, not data mutations in arrays, objects). If you want to avoid that on primitives, you can manually deactivate/activate this on ChangeDetectorRef instance with detach()/ reattach():

    import { ChangeDetectorRef } from '@angular/core';
    
    export class HelloComponent  {
      @Input() name: string;
    
     constructor(private ref: ChangeDetectorRef) {}
    
      public changeName() {
        this.ref.detach();
        this.name = 'Inner';
      }
    }