MaiDeveloper

Introduction to Browser Custom Events

We can use client-side JavaScript's event API to define and dispatch our events using CustomEvent. It can be used to decouple modules, thus improving maintainability and readability. Assume our application needs to conduct a long computation or a network request on a regular basis, and the other functionality or user interface is unavailable while these operations are in progress. We should inform the user by showing a spinner. However, the long computation or a network request should not be concerned with how to notify the user. Instead, it may simply send one event to indicate that something is busy, followed by another event once it is no longer busy. Another user interface module can register event handlers for such events and respond appropriately.

Let's get started with the CustomEvent constructor. It takes two arguments; the first argument is the name of the event, and the second argument is the object which is optional. We can pass any data in the second argument detail regarding the event.

Syntax

/**
 * @typedef  {object}   Options
 * @property {Any}      detail      Optional, default to null
 * @property {boolean}  bubbles     Optional, default to false
 * @property {boolean}  cancelable  Optional, default to false
 * @property {boolean}  composed    Optional, default to false
 */

/**
 * @param {string} name     The name of the event
 * @param {Options} options  Optional
 */

new CustomEvent(name);
new CustomEvent(name, options);

Parameters

name { string }

The name of the event

options { object } optional

Object with the following fields:

detail { object } optional

Any data type that is associated with the event. The default is `null`.

bubbles { boolean } optional

A boolean value indicating whether the event bubbles. The default is false.

cancelable {boolean} optional

A boolean value indicating whether the event can be cancelled. The default is false.

Usage

  1. Create a listener for this event.

document.addEventListener('busy', e => {
  if (e.detail.isBusy) {
    // Show loading spinner
  } else {
    // hide loading spinner
  }
});

  1. Create a custom event using the CustomEvent constructor and then dispatch or trigger the event. We can pass data in the detail parameter.

const busyEvent = new CustomEvent('busy', {
  detail: {
    isBusy: true
  }
});

document.dispatch(busyEvent);

Example

The following is an example of showing the loading spinner before the network request and hiding the loading spinner after the network request has finished.


/**
 * Assume this function calls an network request
 * And takes 60 seconds to finish it
 */
const longNetworkRequest = () => {
  return new Promise((resolve, reject) => {
    // Resolve after 60 seconds
    setTimeout(resolve, 1000 * 60);
  });
};

/**
 * Dispatch busy event
 * @param {boolean} isBusy
 */
const dispatchEvent = isBusy => {
  document.dispatchEvent(new CustomEvent('busy', {
    detail: {
      isBusy
    }
  }))
};

const main = async () => {
  // Notify the user interface that
  // an network request is about to start
  dispatchEvent(true);

  try {
    await longNetworkRequest();
  } catch (err) {
    // Handle error
  } finally {
    // After the network request has finished 
    // either successed or failed
    // Notify the user interface about it
    dispatchEvent(false);
  }
};

Anywhere in your program, you can register a handler for busy events. The following example show or hide the loading spinner.


document.addEventListener('busy', e => {
  if (e.detail.isBusy) {
    // Show loading spinner
  } else {
    // hide loading spinner
  }
});



Mike Mai
Mike Mai   Brooklyn, New York
I am full-stack web developer, passionate about building world class web applications. Knowledge in designing, coding, testing, and debugging. I love to solve problems.