Using Event Bubbling to Your Advantage

Its happened to everyone working with Javascript: you build your test app that handles clicks on elements to do really neat things and everything's going great. You move it live, and as the data starts coming in your app gets slower and slower until finally the system starts to become unusable. Whats the problem? In testing you had maybe five or ten clickables, but your app has been growing, and you've now got 20, 60, 120 or more, and the time it takes to bind all of your click events is skyrocketing. What if you could just use a single handler for all of them?

Thanks to the magic of event bubbling, you can use just a single event handler to handle that even on any number of child elements. How does this work? Well when an event is registered, its passed up the chain of its ancestors until someone handles the event. This means that you can define a single handler on a higher level element to handle all of the events that happen within it.

The Example

Ok, to test this out, lets get a simple example bit of code:

<html>
    <head>
        <title>Test</title>
    </head>
    <body>
        <ul id="test">
            <li>One</li>
            <li>Two</li>
            <li>Three</li>
            <li>Four</li>
        </ul>
    </body>
</html>

Ok, so now lets say that we want to write some Javascript that alerts the contents of an <li /> element when you click on it. In this example you could define four separate click handlers handles like in the following jQuery example:

<script src="jquery-1.3.2.js"></script>
<script>
    
    $(document).ready(function () {
        $('#test li').click(function(event) {
            var elem = $(event.target);
            alert(elem.html())
        });
    });
</script>

Or, you could just drop that " li" from the selector and do it like this:

<script src="jquery-1.3.2.js"></script>
<script>
    $(document).ready(function () {
        $('#test').click(function(event) {
            var elem = $(event.target);
            alert(elem.html())
        });
    });
</script>

Both will work to alert you when you click on the <li /> element, but one uses only a single event handler, rather than four. This scales up so that you could have this single function working over any number of <li /> elements.

The one big "gotcha" with this technique is that the containing element's event handler is going to fire for every event of that type registered on any element inside it. Say you have a mix of <li /> types, and you only want some of them to alert their contents: to handle this you'll have to create some kind of filtering in the event handler itself, rather than just registering a handler on each element of that type. Its a little bit more overhead, but you should still be realizing massive savings.

 

Comments

Ben Nadel's Gravatar This is very interesting stuff; not something that I have played around with nearly enough. When I was reading this, the thought popped into my head - once the event has bubbled up beyond the link, do I still have the opportunity to prevent the default action?

I just ran a test of this, and YES, you do. It seems you can prevent the default and/or stop propagation at any point in the bubbling chain.

Good food for thought!
William Ukoh's Gravatar You have to be aware that the magic here is the use of the "target" property of the "event" object passed into your click handler. Beginners to jQuery usually become accustomed to using $(this) to refer to the target element, and hence would be confused when looking at your code.

The DOM Event model makes us understand that every element triggers an event when interacted with, meaning if you had say,

<ul id="test">
<li>One <a href="anchor">sample link</a></li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
</ul>

and you clicked on the link itself, an event has been triggered (i:e the "click" event). Event bubbling now takes place and the browser searches each parent to see if they have a handler for a click event registered. If any does, it will call the handler function. The interesting thing is that in the "event" object passed to the handler, you can refer to the DOM element that emitted the event using the "target" property. So even if, the handler function was registered on a parent element, any of its child elements can leverage it.

Just as u said, it is a very lovely technique owing to event bubbling in the DOM Event model.
Comments are not allowed for this entry.
Jon Hartmann, July 2011

I'm Jon Hartmann and I'm a Javascript fanatic, UX/UI evangelist and former ColdFusion master. I blog about mysterious error messages, user interface design questions, and all things baffling and irksome about programming for the web.

Learn more about me on LinkedIn.