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.

javascript

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.

javascript

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.

javascript

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.

javascript

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.

javascript

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.

javascript

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.

javascript

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.

javascript

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.

javascript

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.

javascript

const controller = new AbortController();
window.addEventListener('resize', update, { signal: controller.signal });
controller.abort();
All sections expanded. Activate the control to collapse all sections.