DEV Community

Ayako yk
Ayako yk

Posted on

Understanding Event Delegation in JavaScript: From Bubbling to Data Attributes

In the previous blog, we discussed Event Bubbling. When an event occurs on a nested element, it first triggers on the element itself and then bubbles up to its parent elements. Without understanding event bubbling, this behavior might cause unintended issues. However, when used effectively, it can become a powerful tool.

  1. Common Ancestor
  2. Data Attributes: data-*
  3. Combining Data Attributes with event.target

Common Ancestor
When we have many child elements that share the same behavior, it’s inefficient to add target.addEventListener("click", () => {}) to each individual child element. Instead, we can attach the event listener to their common parent (using event.currentTarget). Then, regardless of which child (event.target) is clicked, the event handler will execute.

Here is an example from MDN:

HTML

<div id="container">
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
</div>
Enter fullscreen mode Exit fullscreen mode

JS

function random(number) {
  return Math.floor(Math.random() * number);
}

function bgChange() {
  const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
  return rndCol;
}

const container = document.querySelector("#container");

container.addEventListener("click", (event) => {
  event.target.style.backgroundColor = bgChange();
});
Enter fullscreen mode Exit fullscreen mode

Data Attributes: data-*
The data-* attribute allows you to create custom attributes in HTML. These attributes make it easier to exchange information between HTML and the DOM.

While it still requires adding data-* to each child element, it offers several advantages. Not only can it be used for CSS styling, but it also simplifies management compared to adding individual event listeners to each child element.

The Modern JavaScript Tutorial provides an elegant example:

<div id="menu"> 
    <button data-action="save">Save</button> 
    <button data-action="load">Load</button> 
    <button data-action="search">Search</button> 
</div> 

<script> 
    class Menu { 
        constructor(elem) { 
            this._elem = elem; 
            elem.onclick = this.onClick.bind(this); // (*) 
        } 

    save() { 
        alert('saving'); 
    } 
    load() { 
        alert('loading'); 
    } 
    search() { 
        alert('searching'); 
    } 
    onClick(event) {      
        let action = event.target.dataset.action; 
        if (action) { 
            this[action](); } 
        }; 
    } 
    new Menu(menu);
</script>
Enter fullscreen mode Exit fullscreen mode

Combining Data Attributes with event.target
Using data attributes together with event.target, we can set independent behaviors for elements.

Quick Review: event.target
A reference to the object to which the event was originally dispatched.

Here's an example:

Counter: <input type="button" value="1" data-counter> 
One more counter: <input type="button" value="2" data-counter> 

<script> 
    document.addEventListener('click', function(event) { 
        if (event.target.dataset.counter != undefined) { // if the attribute exists... 
            event.target.value++; 
        } 
    });
</script>
Enter fullscreen mode Exit fullscreen mode

The Modern JavaScript Tutorial

In this example, both buttons use the same data-counter attribute and share a single event listener. However, referencing event.target ensures that they behave independently. Each button retains its own state (value), making this a powerful and efficient approach.

Event bubbling, combined with techniques like using a common ancestor, data-* attributes, and event.target, provides a powerful and efficient way to manage events in JavaScript. Mastering these concepts ensures that events can be handled cleanly and effectively.

Top comments (0)