[SO] Custom Events, bubbles, composed
by Danny Engelman
HTML
<my-component id=ONE></my-component>
<my-component id=TWO composed>
<my-component id=INSIDETWO composed></my-component>
</my-component>
<my-component id=THREE composed bubbles>
<my-component id=INSIDETHREE composed bubbles></my-component>
</my-component>
<script>
let log = (evt, label, ...args) => {
let div = document.createElement("div");
div.classList.add(evt.target.id, evt.type);
div.innerHTML = `${label} received ${evt.type} from ${evt.target.id}`;
console.log(evt.type, evt.target);
document.body.append(div);
}
document.addEventListener("click", (evt) => log(evt, 'document'));
document.addEventListener("MyEvent", (evt) => log(evt, 'document'));
customElements.define('my-component', class extends HTMLElement {
constructor() {
const attr = (x) => this.getAttribute(x),
has = (x) => this.hasAttribute(x) ? x : "",
label = () => `${attr('id')} : ${has('COMPOSED')} ${has('BUBBLES')} `,
html = () => `<button id="${attr('id')}">${label()}</button><br><slot></slot>`;
super().attachShadow({
mode: 'open'
}).innerHTML = html();
let button = this.shadowRoot.querySelector("button");
button.addEventListener("click", (evt) => {
log(evt, `button inside ${this.id}`);
button.dispatchEvent(new CustomEvent("MyEvent", {
bubbles: this.hasAttribute("bubbles"),
composed: this.hasAttribute("composed")
}));
});
this.addEventListener("MyEvent", (evt) => log(evt, this.id)) // same location as DOMlistener below
}
});
[...document.querySelectorAll("my-component")].forEach(el => {
el.addEventListener("MyEvent", (evt) => log(evt, "DOMlistener_" + el.id));
})
</script>
CSS
body{
font:14px arial;
}
div{
padding:.1em .2em;
}
my-component{
padding:.5em;
display:inline-block;
height:1em;
}
#ONE,.ONE{
background:lightcoral;
}
#TWO,.TWO{
background:pink
}
#INSIDETWO,.INSIDETWO{
background:orange;
}
#THREE,.THREE{
background:lightgreen
}
#INSIDETHREE,.INSIDETHREE{
background:gold;
}
.MyEvent{
font-weight:bold;
}