can someone please explain what happens here? am I missing something?
#handleClick() {
this.dispatchEvent(new Event('onClicked'));
}
mySlot.addEventListener('slotchange', () => {
mySlot.addEventListener('click', this.#handleClick); // doesn't work
mySlot.addEventListener('click', () => this.#handleClick()); // works
});
...
myCustomElement.addEventListener('onClicked', (e) => {
console.log(e, e.detail);
});
#handleClick() {
this.dispatchEvent(new Event('onClicked', {bubbles: true, composed: true}));
}
mySlot.addEventListener('slotchange', () => {
mySlot.addEventListener('click', this.#handleClick); // works
});
...
...
myCustomElement.addEventListener('onClicked', (e) => {
console.log(e, e.detail);
});
I know that custom events don't reach the "light-DOM" out of the box, that's why I can understand why we should put "composed: true and bubbles: true". But why do mySlot.addEventListener('click', () => this.#handleClick()) works without the need of making the event "composable"?
Here is a fiddle to better understand the problem: https://jsfiddle.net/rv6w3xj1/1/
Your problem is scope
A Function reference gets a different
thisscope than a Arrow Function definition,thus your
this.dispatchEventis executed on/from different DOM Elements.When that element is inside shadowDOM, it needs
bubbles:true;composed:trueto escape through the shadowRootI pruned your code to the bare minimum,
slotandslotchangehave got nothing to do with thisYou can fix it with oldskool
this.handleClick.bind(this),but that is more error-prone than
(e) => this.handleClick(e)because most junior DEVs won't understand what is going on with
bindTo make 'scope' clearer
Below code displays where
this.dispatchEvent(new CustomEvent('onClicked'originates fromThus showing what
thisis inthis.dispatchEventWhen inside shadowDOM it needs
bubbles:true;composedto escape shadowDOMThe
e.composedPath()clearly shows a different path the "click" Event passed.One click came from
<slot>(inside shadowDOM) the other from your<custom-element>(outside shadowDOM)