10

I have next template of root component, that draws 9 tiles:

<ul>
  <li *ngFor="let x of [0,1,2,3,4,5,6,7,8]">
    <tile></tile>
  </li>
</ul>

and next tile component, where I added HostListener for document click:

import {AfterViewChecked, Component, HostListener} from '@angular/core';

@Component({
  selector: 'tile',
  template: '<p>tile works!</p>'
})
export class TileComponent implements AfterViewChecked {

  ngAfterViewChecked(): void {
    console.log('checked');
  }

  @HostListener('document:click', ['$event'])
  onOutsideClick(event: any): void {
      // do nothing ...
  }

}

Plunker: http://plnkr.co/edit/7wvon25LhXkHQiMcwh48?p=preview

When I run this I see that on each click change detection was called 9^2 times: enter image description here

I can't understand why.

Can somebody explain to me why change detection triggers n^2 times in this case?

Artem
  • 691
  • 5
  • 20
  • Angular patches all dom event listeners so after calling handler angular will perform change detection. You can use `zone.runOutsideAngular` to avoid it This could be also helpful for you https://stackoverflow.com/questions/43108155/angular-2-how-to-keep-event-from-triggering-digest-loop/43294113#43294113 – yurzui Jun 14 '17 at 13:55
  • Looks like it runs change detection for every `@HostListener()` that receives an event. There are 9 component instances that register for the click event. A click event is received by each component instance and then change detection is run for the whole app each time. I don't say that this behavior makes sense, only that I think this is what's happening. – Günter Zöchbauer Jul 03 '17 at 07:56
  • I'm trying to understand is it designed behaviour or bug? If it by design than how to avoid bulk detection change triggering when using @HostListener. – Artem Jul 03 '17 at 08:21
  • 1
    That's by design. – yurzui Jul 05 '17 at 07:43

2 Answers2

5

Short answer - That is by design.

Since we have a click handler, angular triggers change detection after handler been called.

So, when the first component handles click it cause change detection. Then all the components print "checked".

And that repeated for each component, so I've got 9^2 prints "checked."

And one additional note that OnPush strategy will not help to reduce an amount of prints.

Artem
  • 691
  • 5
  • 20
2

@Hostlistener can be costly. Check my answer here to minimize the effect and improve performance. Detect click outside Angular component

ginalx
  • 1,905
  • 1
  • 15
  • 19