Event Delegation in JavaScript

This is the second post in a series on bubbling, delegation and how to delegate events with jQuery. It assumes you’ve already read the first post What does event bubbling mean, or already have a grasp on event bubbling in JavaScript.

Event Delegation

When providing examples, I’m going to refer to the HTML we used as an example in the first post (shown below):

<div>
    <h1>
        <a href="#">
            <span>Hello</span>
        </a>
    </h1>
</div>

Also note that I’m still not interested in adding support to older versions of IE (<9). You’ll have to add the normal fallback to attachEvent instead of addEventListener if you want to support them, and find an alternative for querySelector/ querySelectorAll. The event target property exists as srcTarget in older versions of IE.

So now we understand event bubbling… but how does it help us?

It means if we want to add an event handler for a click on the <span> element in the above example, we don’t need to add it to the <span> element; we can add it to any of it’s ancestors… as shown here;

window.addEventListener('load', function () {
    document.querySelector('div').addEventListener('click', function (e) {
        if (e.target.nodeName === "SPAN") {
            alert('Click event fired on the SPAN element'); 
        }
    }, false);
});

But yes, I hear you ask me again… how does this help us?

Imagine you have a table with hundreds of rows. Each row contains a <a /> to which you want to attach a click handler to. With no event-bubbling you’d have to bind the event handler to each <a />; which involves iterating over each element and adding an event handler individually to each one. See it in action here. Does it feel efficient to you?;

window.addEventListener('load', function () {
    // Add loads of rows
    var rows = '';

    for (var i = 0; i < 100; i++) {
        rows += '<tr><td>' + i + '</td><td><a href="#">Click Here</a></td></tr>';
    }

    document.querySelector("table").innerHTML = rows;
    // End setup

    // Attach event to each element
    var elements = document.querySelectorAll('#the-table a');

    for (var i=0;i<elements.length;i++) {
        elements[i].addEventListener('click', function (e) {
            alert('You clicked row #' + this.parentNode.previousSibling.innerText);
        }, false);
    };

    alert('Event handler bound to ' + elements.length + ' elements');
});

Instead, what we could do is bind one click handler to the <table />.

document.querySelector('#the-table').addEventListener('click', function (e) {
    if (e.target.nodeName === "A") {
        alert('You clicked row #' + e.target.parentNode.previousSibling.innerText);
    }
});

See this in action here.

Secondly, imagine you load some content dynamically and you want some capture some events on it. You can only add event handlers to elements once they exist (makes sense right?), so without event-bubbling you’d have to re-bind the same event handlers to your content each time you add the content.You can see this in an example here, where we add rows to the table programmatically when you click a button.

However, because the <table /> element does exist in the DOM when the page is rendered, we can add an event handler to this no problem, as shown here. This is a common problem when loading elements via AJAX as well; and attaching the event handler to an element that is in the DOM from the page load is the solution.

So in summary, you should be taking advantage of event bubbling by using event delegation if you want to handle an event for multiple elements, or you want to bind events to dynamically loaded data.

Now move onto the next article; Event Delegation with jQuery

3 thoughts on “Event Delegation in JavaScript

  1. Pingback: Javascript Interview Questions | KRIYANCE

  2. Thanks to you, I finally understood why bubbling existed, what it meant and how to use it most efficiently. A big THANK YOU

  3. I have a simple example to explain event bubbling. Consider a country which has set an alert for riots. This example will include violence. 😉 Consider a riot in a town. In this situation it is correct to say that a riot took place in the town. It is also true to say that a riot took place in the city(where the town belongs.). And moving up the hierarchy in the same way we can say that a riot took place in the state(where the city belongs). Now when a click event takes place in a span tag we can say that the event took place in its parent element(because that’s where it resides) and similarly move up the hierarchy till we reach the document element.

Leave a Reply

Your email address will not be published. Required fields are marked *