9

Lets say i have a component structure like this:

AppComponent
    HeaderComponent
    ContentComponent
        TodosComponent
            TodoComponent

If I set HeaderComponent's changeDetection to ChangeDetectionStrategy.OnPush and change something in TodoComponent, still HeaderComponent's ngDoCheck(), ngAfterViewChecked() and ngAfterContentChecked() gets triggered.

What am I missing? Does ngDoCheck gets triggered anyway? If yes, how to determine if a component was checked by ChangeDetection?

Mick
  • 8,203
  • 10
  • 44
  • 66
  • It depends on what is being changed, but you should look at these two links as they explain what can happen in detail. https://stackoverflow.com/questions/38629828/what-is-the-difference-between-onchanges-and-docheck-in-angular-2 https://stackoverflow.com/questions/39795634/angular-2-change-detection-and-changedetectionstrategy-onpush. Based on these it seems that `ngDoCheck` gets triggered regardless of your change detection strategy. – Emin Laletovic Aug 05 '17 at 12:25
  • so did [my answer](https://stackoverflow.com/a/45522199/2545680) help? – Max Koretskyi Aug 11 '17 at 11:15

1 Answers1

16

Yes, that's the correct behavior. The article If you think ngDoCheck means your component is being checked — read this article explains the behavior in great details. Here is the short version.

The ngDoCheck is triggered before the component is being checked. This is done to allow you to perform some custom logic and then mark the component for a check. You know that Angular tracks @Inputs by object references but you can use ngDoCheck to make your custom tracking. Here is the simple example:

Component({
   ...,
   changeDetection: ChangeDetectionStrategy.OnPush
})
MyComponent {
   @Input() items;
   prevLength;
   constructor(cd: ChangeDetectorRef) {}

   ngOnInit() {
      this.prevLength = this.items.length;
   }

   ngDoCheck() {
      if (this.items.length !== this.prevLength) {
         this.cd.markForCheck();
      }
   }

Please bear in mind that ngDoCheck is triggered only for the top level component with the strategy OnPush. It's not triggered for this components children.

Also it is correct that ngAfterViewChecked will be triggered for the component even if now checking was done. This is by design as well.

I highly recommend you to read Everything you need to know about change detection in Angular, specifically Exploring the implications section. It shows the order of operations you're looking for.

Also read Why do we need ngDoCheck.

Peter Hauer
  • 70
  • 1
  • 12
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • 1
    But how to determine if it was actually checked and my changeDetectionStrategy is working fine? – Mick Aug 05 '17 at 13:00
  • sorry, I don't understand. Your component will be checked only if the `@Input` change. why do you need to know that the component was checked. also I highly recommend reading the article to understand the process – Max Koretskyi Aug 05 '17 at 13:06
  • Yes but there is no possibility to confirm it was not checked? I can only know but not be sure. I read a lot of articles and i am pretty sure how this works and what events trigger CD. Im just looking for a way to verify a component has run through CD or not. – Mick Aug 05 '17 at 13:07
  • you have a few options. for example, you can modify some value used in the template in the HeaderComponent using timeout - it won't be reflected in the view. Other option is to listen for lifecycle hooks on children components - no lifecycle hooks will be triggered for them – Max Koretskyi Aug 05 '17 at 13:12
  • Thats the only 2 possibilities i can think of, too. Maybe there should be a new lifecycle-hook? – Mick Aug 05 '17 at 13:16
  • why do you need to check that? if just to make sure that the strategy works those two options should be enough – Max Koretskyi Aug 05 '17 at 13:25
  • 1
    @Mick Just add some code that is executed on every checking view like `{{ testChecking() }}` in template with OnPush and observe – yurzui Aug 05 '17 at 13:49
  • @Mick Or open `HeaderComponent.ngfactory.js` and set breakpoint on `updateDirectives` or `updateRenderer` function but first you need to read more about it in articles that Maximus has written – yurzui Aug 05 '17 at 13:53
  • @Mick Or if you know source code well set breakpoint here https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L612 and observe `view.component`. I prefer watching for `ngfactory.js` – yurzui Aug 05 '17 at 14:01
  • @yurzui, I was going to recommend the breakpoint in sources first but then I decided to stick to `no sources` approach) Besides it's all shown in the article – Max Koretskyi Aug 05 '17 at 14:04