Guides: Dispatching Events
There are a few steps you have to take in order to dispatch an event from your custom element:
- Use the function syntax to define your component. This will give you access to
this
, the instance of your custom element. - When defining your callback that you wish to dispatch from, make sure it is bound to
this
. You can do this by using the fat arrow syntax. - Finally, you can create a
new CustomEvent
and pass that tothis.dispatchEvent
.
Here are a couple of examples of dispatching events from a haunted custom element:
function Product({ name, price, productId }) {
const buyProduct = () => {
const event = new CustomEvent('buy-product', {
bubbles: true, // this let's the event bubble up through the DOM
composed: true, // this let's the event cross the Shadow DOM boundary
detail: { name, price, productId } // all data you wish to pass must be in `detail`
});
this.dispatchEvent(event);
}
return html`
<article>
<h3>${name}</h3>
<p>Price: ${price} USD</p>
<button @click=${buyProduct}>Purchase</button>
</article>
`;
}
Product.observedAttributes = ['name', 'price', 'product-id'];
With this, you can now listen for the buy-product
event either on an instance of <store-product>
itself or higher up in the DOM. Here are examples of both of these instances:
Listening on an element
function Store() {
const [{ name }, setPurchased] = useState({});
return html`
<store-product
name="T-Shirt"
price="10.00"
product-id="0001"
@buy-product=${event => setPurchased(event.detail)}
></store-product>
<p ?hidden=${!name}><output>${name} Purchased</output></p>
`;
}
Listening higher up in the DOM
import { component, html, useEffect, useState } from 'haunted';
import './my-store.js';
function App(element) {
const [report, setReport] = useState('');
useEffect(() => {
// Because the event bubbled all the way up here,
// we can listen directly on this web component itself! 🎉
const onBuyProduct = ({ detail: { productId }}) =>
setReport(`product id ${productId} ordered`);
element.addEventListener('buy-product', onBuyProduct);
// very important to remove the event listener!
return () =>
element.removeEventListener('buy-product', onBuyProduct);
}, []); // make sure you list all dependencies
return html`
<my-store></my-store>
<p><output>${report}</output></p>
`;
}
customElements.define('my-app', component(App));
<my-app></my-app>
<script type="module" src="app.js"></script>
import { html, component, useState } from 'haunted';
import './store-product.js';
function Store() {
const [{ name }, setPurchased] = useState({});
return html`
<store-product
name="T-Shirt"
price="10.00"
product-id="0001"
@buy-product=${event => setPurchased(event.detail)}
></store-product>
<p ?hidden=${!name}><output>${name} Purchased</output></p>
`;
}
customElements.define('my-store', component(Store));
import { component, html } from 'haunted';
function Product({ name, price, productId }) {
const buyProduct = () => {
const event = new CustomEvent('buy-product', {
bubbles: true, // this let's the event bubble up through the DOM
composed: true, // this let's the event cross the Shadow DOM boundary
detail: { name, price, productId } // all data you wish to pass must be in `detail`
});
this.dispatchEvent(event);
}
return html`
<article>
<h3>${name}</h3>
<p>Price: ${price} USD</p>
<button @click=${buyProduct}>Purchase</button>
</article>
`;
}
Product.observedAttributes = ['name', 'price', 'product-id'];
customElements.define('store-product', component(Product));
If you want to look more into firing events, here are some links:
CustomEvent
— MDNEvent
— MDNdispatchEvent
— MDN- Creating and triggering events — MDN
- "Shadow DOM and Events" — Ilya Kantor