angularangular2-changedetectionchange-detector-ref

Principe of Angular OnPush + Change detection work


There is 3 components: Parent, Child, ChildChild:

@Component({
  template: `<div>{{parentProp}}</div> <child-component></child-component>`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentComponent {
  public parentProp: string = 'parentValue1';

  constructor(){}

  ngOnInit() {
    setTimeout(() => this.parentProp = 'parentValue2', 2000)
  }
}

@Component({
  selector:'child-component',
  template: `<div>{{childProp}}</div> <child-child-component></child-child-component>`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentComponent {
  public childProp: string = 'childValue1';

  constructor(private cdr: ChangeDetectorRef){}

  ngOnInit() {
    setTimeout(() => {
        this.childProp = 'childValue2';
        thic.cdr.markForCheck();
    }, 10000);
  }
}

@Component({
  selector:'child-child-component',
  template: `<div>{{childChildProp}}</div>`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentComponent {
  public childChildProp: string = 'childChildValue1';

  constructor(){}

  ngOnInit() {
    setTimeout(() => this.childChildProp = 'childChildValue2', 3000);
  }
}

Parent -> Child -> ChildChild. All of them are OnPush. On parent and childChild there is no changeDetectorRef, and setTimeout on 3 seconds where their template properties are changing. On central - Child, there is setTimeout on 10 seconds which changes its template property AND changeDetectorRef which does markForCheck(). WHen it is executed, Child component is marked for check and becomes rerendered, and it comes above and does Parent component marked for check. And after 10 seconds when it was done, parent component rerenders and shows the changed value of its prop. But as I know after it comes above (from child to parent), and then it comes below (parent -> child -> childChild) and should mark for check also childChild component. But it doesnt.

Next, if I change markForChecked() to detectChanges() in Child, it should rerender Child (and it does) and its children (childChild). But childChild is not rerendered.

Can you tell me what happens?


Solution

  • markForCheck() marks the component where it is called and all its OnPush ancestors to be checked. I.e. if it is called in "child" it will mark "child" and "parent", but not "childChild". The change detection cycle respects the ChangeDetectionStrategy and will therefore not check "childChild"

    detectChanges() checks the component where it is called and all children, but again respecting the ChangeDetectionStrategies of the children. This is why "childChild" is not checked.