angular: @angular/elements component events are called from an inconsistent zone

I’m submitting a…


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:

Current behavior

Event handlers in an angular element (registered as a custom element with @angular/elements), are called either from the angular zone or from the root zone depending on how the element is instantiated, leading to different behaviors:

  • if the element is in the initial markup of the page (before the custom element is registered), then event handlers are called from the angular zone (as expected), and the change detection and refresh of the template are done correctly
  • if the element is created from the angular zone (after the custom element is registered), then event handlers are called either from the angular zone (in Chrome, leading to a correct behavior) or from the root zone (in other browsers, leading to an incorrect behavior: the change detection is not done and the template is not refreshed)
  • if the element is created from the root zone (after the custom element is registered), then event handlers are called from the root zone (both in Chrome and other browsers), leading to an incorrect behavior: the change detection is not done and the template is not refreshed.

Expected behavior

The angular element should behave correctly no matter how it is instantiated. In the minimal reproduction sample, clicking on “Toggle display” should work no matter the line.

Minimal reproduction of the problem with instructions

https://stackblitz.com/edit/angular-dxu5td?file=src%2Fapp%2Fhello.component.ts Depending on the line and the browser, clicking on the “Toggle display” works or has no effect. In Chrome, only the first two lines work correctly. In other browsers, only the first line works correctly.

What is the motivation / use case for changing the behavior?

The current behavior is inconsistent. Event handlers should be called from the angular zone no matter how the component is instantiated, which would allow those components to be created from any other framework even if that framework does not run in the angular zone.

Environment


Angular version: 6.0.3

Browser:
- [x] Chrome (desktop) version 66.0.3359.181
- [x] Firefox version 60.0.1
- [x] IE version XX
- [x] Edge version XX

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 6
  • Comments: 19 (13 by maintainers)

Commits related to this issue

Most upvoted comments

What is the plan on this? Having an opportunity to export existing AngularComponents and use them in non Angular or legacy AngularJS application with Zone/Change Detection working out of the box would be a huge use case for my company (and for many others with legacy / non angular systems i believe)

@robwormald , I agree an additional ElementStrategy/Factory is better, by checking current NgZone is using zone.js or noopzone, we can use different Strategy.

And do you have chance to take a look at my proposal? https://github.com/JiaLiPassion/angular-elements-with-zone I believe we can make zone.js only active inside Angular Elements without impact outside world, so user can have another option to develop Angular Elements. The benefits of this idea are :

  1. user can develop Angular Elements just like developing normal Angular Components.
  2. user can easily migrate existing Angular Components to Angular Elements.

Please check it when you have time. Thank you!

@robwormald, At my company there is a big opportunity for using elements in older applications – and the developers are used to change detection that Just Works™, so I think the zone use case brings a lot of value.

So you are thinking something like this to enable zones:

const strategyFactory = new ComponentNgElementZoneStrategyFactory(HelloComponent, injector); const customElement = createCustomElement(HelloComponent, { injector, strategyFactory });

and then a strategy with methods something like this?

connect(element: HTMLElement) { this.insureAngularZone( () => { super.connect(element);});} private insureAngularZone(fn: () => any) { NgZone.isInAngularZone() ? fn() : this.ngZone.run(fn); }

I’ll update the PR

In which version will the issue be fixed. Any expected timeline ?