JavaScript Events - Exercise 3
Create a CustomEvent, place application data in detail, and dispatch it from an element. Keep the handler focused on the event and use the event object when you need more details.
const event = new CustomEvent('cart:updated', {
detail: { total: 42 }
});
cart.dispatchEvent(event);Subscribe using the same event name and read the payload from event.detail. Keep the handler focused on the event and use the event object when you need more details.
cart.addEventListener('cart:updated', (event) => {
totalLabel.textContent = `$${event.detail.total}`;
});Create an AbortController and pass its signal to each listener. Calling abort() removes them together. The example shows the same rule with a small handler that can run in the browser.
const controller = new AbortController();
window.addEventListener('resize', refresh, { signal: controller.signal });
document.addEventListener('visibilitychange', refresh, { signal: controller.signal });
controller.abort();Use an async callback with try/catch so a rejected request is handled instead of becoming an unhandled rejection. Keep the handler focused on the event and use the event object when you need more details.
button.addEventListener('click', async () => {
try {
const response = await fetch('/api/profile');
render(await response.json());
} catch (error) {
showError(error);
}
});Store the latest coordinates and schedule one visual update with requestAnimationFrame(). Keep the handler focused on the event and use the event object when you need more details.
let frameId;
window.addEventListener('pointermove', (event) => {
latestPoint = event;
if (!frameId) frameId = requestAnimationFrame(updateCursor);
});Use passive: true for high-frequency listeners when the handler will not call preventDefault(). Keep the handler focused on the event and use the event object when you need more details.
window.addEventListener('touchmove', trackTouch, {
passive: true
});Keep setup and teardown together: register listeners during initialization and abort their shared signal during destruction. Keep the handler focused on the event and use the event object when you need more details.
function mountPanel(panel) {
const controller = new AbortController();
panel.addEventListener('click', handleClick, { signal: controller.signal });
return () => controller.abort();
}Ignore editable targets before matching the shortcut, then prevent the default action only when the shortcut is handled. Keep the handler focused on the event and use the event object when you need more details.
document.addEventListener('keydown', (event) => {
const editable = event.target.matches('input, textarea, [contenteditable]');
if (editable || event.key !== 'k' || !event.ctrlKey) return;
event.preventDefault();
openSearch();
});Use event.target for the element that originated the event and event.currentTarget for the element whose listener is running. This distinction matters with delegation.
list.addEventListener('click', (event) => {
console.log(event.target, event.currentTarget);
});Create an AbortController, pass its signal to related listeners, and call abort() when the group is no longer needed. This keeps cleanup in one place.
const controller = new AbortController();
window.addEventListener('resize', update, { signal: controller.signal });
controller.abort();