Open tjsavage opened 7 years ago
@tjsavage @arthurevans I would like to help with this but need someone's brains to pick. Can you recommend anyone on the Polymer team I can ask?
I believe @kevinpschaaf mentioned this to me originally
Thanks @tjsavage, I will follow up with @kevinpschaaf.
I think the two main use cases for firing events are:
I want to fire a non-bubbling event (only my host can listen, by adding listener directly on me):
this.dispatchEvent(new CustomEvent('my-event'));
I want to fire a bubbling event that anyone all the way up the tree can see (what fire
did by default):
this.dispatchEvent(new CustomEvent('my-event', {bubbles: true, composed: true}));
The new thing in ShadowDOM v1 is the ability to fire a bubbling event that stops at the nearest shadow root ("Use Case 3"). This means any light dom parent all the way up to the shadowRoot
can catch the event via delegation, but nothing outside of the shadow root including the host element.
this.dispatchEvent(new CustomEvent('my-event', {bubbles: true}));
Since this is new and we've lived with (1) and (2) for so long, it's hard to come up with critical use cases where you need this capability. However, I hesitate to say it's not useful. It's just a thing you can do now, a tool in the toolbox that might prove useful. But I don't think we can give concrete guidance on when to use 2 vs. 3 yet.
As for the listening side, the only thing affected by any of this is that events fired per (3) ({bubbles: true, composed: false}
) within a host's shadow root can only be caught on children of the shadowRoot
or on the shadowRoot
itself (in v1 shadowRoot
now has an addEventListener
interface for this purpose; in v0 it didn't). What this means is that a host should do this.shadowRoot.addEventListener
to catch a bubbling but non-composing event coming up from its shadow children, since it won't fire on the host element itself (composed: false
means it stops at the shadowRoot
).
Other than that, not much else is affected on the listening side. The direct replacement for listeners: { event: handler }
is just this.addEventListener('event', e=>this.handler(e))
, and its generally safe to do this from the constructor
. However, a main reason we removed listeners
as sugar is that we don't want to decide when in the element's lifecycle we add the listener (because adding listeners is startup work that can have cost). Instead, we want the author to decide when to add the listener by writing that code at the appropriate spot for their element.
Particularly, there is generally no reason to add UI event listeners (click
, mousemove
) prior to first paint, since it's impossible for those events to be generated from the user before pixels have drawn on the screen. So for a large class of events, it's better to do Polymer.RenderStatus.afterNextRender(()=>this.addEventListener('event', e=>this.handler(e)))
from e.g. constructor so that the work to add the event doesn't block the critical first paint. However, other patterns like building a list of children based on them firing events as they are created requires adding the listener early (e.g. synchronously in constructor). So we'd just like users to consider when the listener is needed and add it at the appropriate time.
Are there any performance benefits to using:
this.dispatchEvent(new Event('my-event'));
VS
this.dispatchEvent(new CustomEvent('my-event'));
when not passing data through detail
?
Thanks @kevinpschaaf. Some of this is currently covered in https://www.polymer-project.org/2.0/docs/devguide/events#custom-events but we can do a better job of giving prescriptive advice on where to add event listeners, and why.
From @tjsavage on December 8, 2016 19:59
With #UseThePlatform and removing some of the sugaring around dispatching events, there are now some gaps in 2.0 that can make managing custom events harder to figure out - especially with how events bubble and behave across shadow roots. This can be fixed with documentation, perhaps on the README in the short-term (before launch).
Particularly -
this.fire
andlisteners
block helped a lot with event handling. Can we explain how to get to "sensible defaults" with lower-level event firing? e.g. "You want to do X with your event => Here's how you set it up"?Copied from original issue: Polymer/polymer#4207