The Classic Case for Event Delegation

Event delegation in JavaScript is the concept of using a single event listener to manage all of the mouse and keyboard events on a given page thus improving performance.

Often web developers will assign an event listener to each element that is associated with some effect or bit of AJAX. For example, perhaps I have three buttons on a page each of which will initiate a specific and unique animation when a user clicks. I could simply add an event listener to each button, and, in truth, if I only had three of these on my page, it would be no big deal in terms of performance. But a better way of managing this scenario would be to add an event listener to an element that contains all three buttons (for example a document, div, or ul) and then determine where the event was triggered.

Event Capturing and Bubbling

Event delegation is possible thanks to event capturing and bubbling. According to JavaScript guru Nicholas C. Zakas, both are concepts that date back to early browser development when engineers needed to understand what should happen when a user interacted with some element on the page. Netscape Navigator solved the problem by creating event capturing, which is the idea that when an event is triggered it starts at the highest relative level of the document (document to body to div to ul to li to button). Internet Explorer’s engineers solved the problem with event bubbling, which initiates the event at the lowest relative level of the document and bubbles it up to the highest level (button to li to ul to div to body to document).

Of the leading web browsers on the market today, all except Internet Explorer support both event capturing and event bubbling. IE chooses not to participate in the web development community and only supports bubbling, which does limit what a developer can do with event delegation if that developer wants to be browser inclusive—usually a must for ecommerce. But focusing on event bubbling is still sufficient to implement event delegation and boost site performance.

The Classic Example: A Table with a 1000 Cells

Each time a web developer adds an event listener to a page, an attachment is created between that page and the DOM. The more often we touch the DOM the more we effect web site performance.

an example of a large HTML table

Imagine that your company sells a highly configurable product with ten performance options and 100 possible configurations. If you wanted to list these options and configurations in a table for comparison purposes, you’d have a large 1,000-cell HTML table to contend with. Now imagine that you wanted to make columns in that table draggable and sortable. And you also wanted to make each cell initiate a custom animation when it was clicked. How many event listeners would you need?

One, if you used event delegation, or at least 1,000 browser-crashing listeners if you assigned each at the point of the click. In the latter case your code might look something like this:


document.getElementById("td-1").onclick = function(event)
{
    reconfigPrice(some, some, some);
};
document.getElementById("td-2").onclick = function(event)
{
    aniSpecs();
};
document.getElementById("td-3").onclick = function(event)
{
    toolTips();
};
…
document.getElementById("td-1000").onclick = function(event)
{
    selfDistruct();
};

To achieve the same end with event delegation, I would still need a lot of code, but only one listener attached to the DOM. I would start by placing that single listener on a containing element, for example the document itself or a table element as in the above example.

Standard web browsers like Firefox, Opera, Chrome, and Safari support the Worldwide Web Consortium’s (W3C) event object, but IE does not. I need to write code that will work for any modern browsers and IE, thus event is equal to event in the aforementioned modern browsers and window.event in IE. Likewise, the variable target is assigned a value of event.target or event.srcElement based on which web browser is interpreting the code.


document.onclick = function(event){
    event = event || window.event;
var target = event.target || event.srcElement;

Next, following Zakas’ examples, I use a switch statement to create multiple branches, so that when an event occurs the browser will evaluate each case until if finds the proper one or stops (break).


    switch(target.id){
        case "td-1":
            reconfigPrice(some, some, some);
            break;
        case "td-2":
            aniSpecs();
            break;
        case "td-3":
            toolTips();
            break;
        …
	case "td-1000"
	    dontSelfDistruct();
	    break;
    }
};

As I mentioned above, there is still a lot of code to be written and implemented, but at least I am not creating a 1,000 unnecessary connections to the DOM.

This post was contributed by our guest columnist Armando Roggio. Armando is a journalist, web designer, technologist and the site director for Ecommerce Developer.

Tags:


Related Articles

© 2014 Get Elastic Ecommerce Blog. All rights reserved. Site Admin · Entries RSS · Comments RSS
The opinions expressed here are of the individuals and do not necessarily reflect the views of Elastic Path.