question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Change detection not triggering for template event handler

See original GitHub issue

🐞 bug report

Description

I am working on an Angular gallery library (repository) and I have a change detection problem with the navigation arrows. The first navigation arrow looks like this in the template:

<div *ngIf="showPrevArrow" class="prev arrow" (click)="prev()">
  <doe-chevron-icon
    *ngIf="!arrowTemplate; else arrowTemplate"
  ></doe-chevron-icon>
</div>

Important part is the click event handler and ngIf on the div. Now everytime it is clicked, the prev method should be called AND change detection should run. This works most of the time:

enter image description here

But in a certain scenario (see reproduction steps), the change detection is not triggered after click which then looks like this:

enter image description here

When I wrap contents of prev method in ngZone.run(() => {...}, the change detection always fires. That’s good, but still, I shouldn’t be supposed to do that in such a rudimentary case.

🔬 Minimal Reproduction

  1. go to https://stackblitz.com/edit/ngx-doe-gallery-x1mbws
  2. in the first gallery, swipe to the 2nd picture
  3. now click prev arrow to go back to 1st picture
  4. have a look at the image counter, it indicates the second picture is still selected

🌍 Your Environment

Angular Version:


Angular CLI: 8.3.20
Node: 12.16.3
OS: linux x64
Angular: 8.2.14
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package Version

@angular-devkit/architect 0.803.20
@angular-devkit/build-angular 0.803.25
@angular-devkit/build-ng-packagr 0.803.25
@angular-devkit/build-optimizer 0.803.25
@angular-devkit/build-webpack 0.803.25
@angular-devkit/core 8.3.20
@angular-devkit/schematics 8.3.20
@angular/cdk 8.2.3
@angular/cli 8.3.20
@angular/material 8.2.3
@ngtools/webpack 8.3.25
@schematics/angular 8.3.20
@schematics/update 0.803.20
ng-packagr 5.7.1
rxjs 6.4.0
typescript 3.5.3
webpack 4.39.2

Anything else relevant? The issue is not platform or browser specific. I tried with angular 9 with the same results.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:12 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
mheverycommented, Jul 30, 2020

Here is my understanding: In ngOnInit you escape ngZone and than call this.cd.detectChanges() outside ngZone Since this.cd.detectChanges() causes *ngIf to instantiate a template that template’s click handler will be registered outside of the ngZoneas a result clicking on the registered event handler will execute handler function outside of the ngZone hence your observation.

Yes this works as expected (correct behavior) and Yes it is surprising.

So the question is what can we do to make it less surprising.

One mental model which we could adopt is to say that all event handlers registered from the (event) syntax always run with NgZone currently installed no matter how the this.cd.detectChanges() was actually called. This would actually align it nicely with #38236. There would be few perf advantages to this so I think it would be worth a try.

  1. Change EventManager so that addEventListener is always done with element.__zone_symbol__addEventListener. This will effectively make sure that all registration will happen outside of the Zone, which should improve performance.
  2. Change the function wrapListener so that it will always execute the listenerFn in the NgZone provided.

The result is that no matter how the template was created, we can be sure that he template behaves consistently (We also save on the registration as we don’t have to pay for the zone.js registration overhead)

I don’t know if such change to the mental model would pass google3 but the only way to know is to implement and try.

NOTE: One place where I could see an issue is that in DebugNode we use zone.js to retrieve callbacks for testing, which we may have to solve in a different way.

1reaction
daelmaakcommented, May 13, 2020

I tried ng 9 again and the problem persists. I also copied the SO Q over. About narrowing the problem down, that won’t be easy as this repro is about a library which is an integral whole, but I’ll see what I can do.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Angular click event handler not triggering change detection
My guess is the change detection is triggered when clicked, but as it starts from the root component and root component has OnPush...
Read more >
Angular click event handler not triggering change detection ...
This all boils down to a following takeaway: Declaring event handlers in a template doesn't automatically guarantee change detection in all scenarios.
Read more >
The Last Guide For Angular Change Detection You'll Ever Need
Be careful, the following actions do not trigger change detection using the OnPush change detection strategy: setTimeout. setInterval.
Read more >
Angular OnPush Change Detection - Avoid Common Pitfalls
If we click on the "Subscribe" button, we will see that now the template shows "Hi Bob", so the triggering of event handlers...
Read more >
Avoid common pitfalls when using OnPush change detection ...
@Component({ selector: 'app-this-dot', changeDetection: ChangeDetectionStrategy.OnPush, template: ... }) export class ThisDotComponent ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found