Event delegation is a powerful technique that allows us to handle events efficiently in a dynamic DOM. Traditionally, event listeners are registered directly on individual elements. However, when new elements are added dynamically, we need to remember to register new event listeners for them.

In the past, jQuery’s .on() method has been a popular choice for event delegation. It allows us to attach an event handler to a parent element and have it executed for specific child elements. This means that even if new child elements are added to the DOM after the event handler is registered, they will still trigger the event.

However, with the rise of modern JavaScript and the availability of native DOM manipulation methods, we can achieve the same functionality using vanilla JavaScript. Let’s see how.

First, we need to create our own on() function. This function takes four parameters: a wrapper selector, an event type (e.g., 'click'), a child selector (to match descendants of the wrapper selector), and an event handler function.

const on = (selector, eventType, childSelector, eventHandler) => {
  const elements = document.querySelectorAll(selector);

  for (const element of elements) {
    element.addEventListener(eventType, eventOnElement => {
      if (eventOnElement.target.matches(childSelector)) {
        eventHandler(eventOnElement);
      }
    });
  }
};

In this function, we select all elements that match the wrapper selector using querySelectorAll(). Then, we loop over each element and register an event listener for the specified event type. Inside the event listener, we check if the event target matches the child selector. If it does, we call the provided event handler function and pass the event object to it.

To use this on() function, we simply invoke it with the desired parameters. For example:

on('ul', 'click', '.module.complete', event => {
  const item = event.target;
  // ... your event handler code
});

In this example, we attach a click event handler to all ul elements. When a click event occurs on an element that matches the .module.complete selector, the provided event handler function will be executed. Inside the event handler, we can access the clicked element using event.target.

By using event delegation with vanilla JavaScript, we can streamline event handling for dynamically added elements without the need for a library like jQuery.