We use cookies to enhance your experience on the site
CodeWorlds

Custom Events

In Jurassic Park, different systems must cooperate - the dinosaur monitoring system must inform the security center about threats, and the security center must notify rescue teams. Standard browser events (click, keydown, submit) handle user interactions, but what if we need custom messages between application modules? This is where Custom Events come to the rescue - custom, non-standard events.

Creating a CustomEvent

The

CustomEvent
constructor allows you to create an event with any name and pass additional data through the
detail
property:

1// Syntax: new CustomEvent(eventName, options)
2const alertEvent = new CustomEvent('dinoAlert', {
3  detail: {
4    species: 'Velociraptor',
5    zone: 'B6',
6    threatLevel: 9
7  },
8  bubbles: true,      // Whether the event bubbles up the DOM tree
9  cancelable: true     // Whether it can be canceled via preventDefault()
10});

The

detail
property can contain any data - objects, arrays, strings, numbers. This is the main difference between
CustomEvent
and a regular
Event
, which doesn't have a
detail
field.

Dispatching Events with dispatchEvent()

To "fire" an event, we use the

dispatchEvent()
method on any DOM element:

1// Dispatching an event on a specific element
2const monitorPanel = document.getElementById('monitor-panel');
3monitorPanel.dispatchEvent(alertEvent);
4
5// Dispatching an event on the entire document (global broadcast)
6document.dispatchEvent(alertEvent);

When an event is dispatched, all registered listeners for it are called synchronously - in the order they were registered.

Listening for Custom Events

Listening for Custom Events works identically to standard events - using

addEventListener()
:

1// Listening on any element
2document.addEventListener('dinoAlert', function(event) {
3  const { species, zone, threatLevel } = event.detail;
4
5  console.log(`ALERT: ${species} detected in zone ${zone}!`);
6  console.log(`Threat level: ${threatLevel}/10`);
7
8  if (threatLevel >= 8) {
9    activateEmergencyProtocol(zone);
10  }
11});

Practical Park Alert System

Let's combine all elements into a complete inter-module communication system:

1// Module 1: Alert generator
2function createParkAlert(alertType, message, data = {}) {
3  const alertEvent = new CustomEvent('parkAlert', {
4    detail: {
5      type: alertType,
6      message: message,
7      timestamp: new Date(),
8      data: data
9    },
10    bubbles: true
11  });
12
13  document.dispatchEvent(alertEvent);
14}
15
16// Module 2: Central listening system
17document.addEventListener('parkAlert', (e) => {
18  const { type, message, timestamp, data } = e.detail;
19
20  console.log(`${timestamp.toLocaleTimeString()} - Alert ${type}: ${message}`);
21
22  switch(type) {
23    case 'security':
24      showSecurityAlert(message, data);
25      break;
26    case 'maintenance':
27      showMaintenanceNotification(message, data);
28      break;
29    case 'visitor':
30      showVisitorInfo(message, data);
31      break;
32    default:
33      showGeneralAlert(message);
34  }
35});
36
37// Module 3: Dinosaur escape detection
38function handleDinosaurEscape(dinosaurId) {
39  const dinosaur = getDinosaurById(dinosaurId);
40
41  createParkAlert('security', `ALARM! ${dinosaur.name} escaped from the enclosure!`, {
42    dinosaurId: dinosaurId,
43    location: dinosaur.enclosure,
44    dangerLevel: dinosaur.dangerLevel
45  });
46
47  activateEmergencyProtocols();
48}

Event Bus Pattern

Custom Events allow you to build a simple Event Bus - a central communication point between independent application modules:

1class ParkEventBus {
2  constructor() {
3    this.target = new EventTarget();
4  }
5
6  emit(eventName, data) {
7    this.target.dispatchEvent(
8      new CustomEvent(eventName, { detail: data })
9    );
10  }
11
12  on(eventName, callback) {
13    const handler = (e) => callback(e.detail);
14    this.target.addEventListener(eventName, handler);
15    // Return a function to unsubscribe
16    return () => this.target.removeEventListener(eventName, handler);
17  }
18}
19
20const bus = new ParkEventBus();
21
22// Monitoring module subscribes to alerts
23const unsubscribe = bus.on('fenceBreak', (data) => {
24  console.log(`Fence in zone ${data.zone} damaged!`);
25});
26
27// Sensor module sends alert
28bus.emit('fenceBreak', { zone: 'C3', voltage: 0 });
29
30// When the module is destroyed - unsubscribe
31unsubscribe();

Thanks to Event Bus, modules don't need to know about each other - they communicate exclusively through events, which ensures loose coupling and easier testing.

Go to CodeWorlds