HTML5, CSS3, jQuery, JSON, Responsive Design...

Delegate your JavaScript events!

Michael Brown   February 20 2015 04:16:59 AM
I looked at a web project today where Allan Jardine's Visual Event plug-in reported nearly 20,000 event handlers on a single page app!

The app was generating a huge table of information, and every row in that table needed something to happen when the user double-clicked on that row.  So to achieve this, the developer had a added a separate event to each row of the table.  "The fool", I thought!  Doesn't the guy know about event delegation?

Well, I was wrong.  The developer did know about event delegation, and had added his events that way.  There was only one event on that table, not 20,000.  But the Visual Event plug-in is incapable of distinguishing between delegated events and individual events when doing its count.  The developer is aware of the problem.

So what's the difference between delegated events and individual events, and why should you be using the former in preference to the latter?


Individual Events

Here's a sample table with about 1000 rows in it:
http://www.users.on.net/~mikeandgeminoz/event.test/non-delegated.html

Each row will pop-up a alert box when you click on that row.  To achieve this, I added events to each individual row in the table using jQuery, like so:
$('#myTable tbody tr').click(function () {
alert("hey " + $(this).attr("data-payload"));
});



Firefox's HTML Inspector tool (note: the built-in one, and not Firebug) shows you this:

Image:Delegate your JavaScript events!

See how each row in the table is marked with a separate "ev" tag?  That's because each row in the table has its own associated event tag.   This is bad.  Each event handler takes up browser resources.  Too many event handlers on your page and your app will slowly grind to a halt.

So, wouldn't it be good if we could achieve the same result, but with only a single event handing all of our tables?  Yes, it would - is, in fact!  This is what event delegation gives us.


Delegated Events

Here's that same 1000 row table again, but this time it's using a delegated event:
http://www.users.on.net/~mikeandgeminoz/event.test/delegated.html

Here's how to add a single event handler for the table's rows, using event delegation:
// For jQuery before version 1.7
$('#myTable tbody').delegate('tr', 'click', function () {
alert("hey " + $(this).attr("data-payload"));
});

// For jQuery 1.7 and higher, where the .delegate() method is deprecated.
$('#myTable tbody').on('click', 'tr', function () {
   alert("hey " + $(this).attr("data-payload"));
});



Note that we're telling the select handler here to target the table's tbody, instead of targeting all of its tr rows, as we did in the first example.  This will give us a single click event, on the table's tbody.  The .on() call or the (now deprecated) delegate() call denotes which elements within that tbody we're actually interested in, which is all of its tr rows.  NB: the syntax of the .on() call is important here: it must contain our target element, "tr" in this case, as its second parameter, otherwise it won't delegate the event handler.

The Firefox HTML Inspector confirms that we have only a single event now:

Image:Delegate your JavaScript events!

What we end up with is a single event handler, at the tbody level, which is still able to ascertain which TR row within the tbody you the user actually clicked on.  Bingo!


Update 21/02/2015

Incorporated Mark Roden's comments below, to say that the .delegate() is now deprecated and that we should now be using the .on() method instead.
Comments

1Mark Roden  02/20/2015 9:22:55 AM  Delegate your JavaScript events!

Thanks for sharing :)

I believe this will do the same (assuming my selector is correct).

$('Body').on('click', '#myTable tbody TR', function () {

alert("hey " + $(this).attr("data-payload"));

});

Event delegation works by using the bubbling up effect of the JavaScript event model. When you click on the table row you are actually clicking on every element going up the DOM tree from that (ultimately to the body) the event is fired for every element and contains a reference to the original element which was clicked. This allows you to look from the top down and find out if the event triggered matches the original target.

As of jQuery 1.7, .delegate() has been superseded by the .on() method

This is an excellent article on the subject for reference :)

{ Link }

thanks again :)

Marky

2Michael Brown  02/20/2015 10:31:15 PM  Delegate your JavaScript events!

Thank you, Mark.

I've now updated the article with your comments about the .delegate() method being deprecated.

I changed my second example link to use .on() instead of .delegate().

About