Event delegation is a technique whereby you use a single event handler on a parent element to listen for interactions that affect the parent's descendant elements; because events on the descendant elements will bubble up to the parent, this can be a reliable and extremely efficient mitigation strategy for reducing the number of resource-consuming event handlers you have on any given page. (You can read more about Event Delegation in this YUIBlog article.)
In the example below, mousing over or clicking on the list items will report their ID attributes in the Logger window on the right side of the screen. Because we're using event delegation, only one event listener is needed for each type of event (
mouseover) to handle the event response for
n list items. Even if there were 100 list items, we'd still just need one event handler per event type.
Event delegation refers to the use of a single event listener on a parent object to listen for events happening on its children (or deeper descendants). Event delegation allows developers to be sparse in their application of event listeners while still reacting to events as they happen on highly specific targets. This proves to be a key strategy for maintaining high performance in event-rich web projects, where the creation of hundreds of event listeners can quickly degrade performance.
This example illustrates the use of event delegation (via the Event Utility) on both
mouseover events. The problem we will solve here involves reacting to
mouseover events on list items. We will assume that there can be many list items and that we want to be frugal in applying event listeners. At the same time, we want to know exactly which
<li> was involved in a
To do this, we'll rely on DOM event bubbling — the process by which an event progresses from its direct target up through the target's node ancestry until it reaches the
window object. The graphic below may help to illustrate the flow: In this case, we'll count on the fact that a click or a mouseover on (A) the text node within an
<li> progresses to the
<li> element itself (B), then to the
<ul> element (C), and then to the list's parent
<div> (D) and so on up the document:
Because events flow this way, we can count on events happening to our
<li>s bubbling up to our <div> whose ID attribute is "container."
We'll start with some structural markup — a
<div> containing a
<ul> with 6
<li> children. Note that our list items have ID attributes — this gives us a way to uniquely identify them when we process
mouseovers at the container level.
We'll use the YUI Logger Control as the reporting mechanism for our event handlers, so this example begins its script by creating a LogReader instance and rendering it into the document body when the
load event fires:
Now we'll add an event handler to the container
<div>, listening for any clicks within its bounds. We're only really interested in clicks on
<li>s, though; when we get one of those, we'll write out a message to the Logger.
The same technique works for the
mousemove event as well. We'll substitute
click, but make no other substantive changes:
In this example, we've used two event listeners with their associated memory and performance load to serve as delegates for the same two events on six list items. Instead of 12 event listeners, we now have two. And the code works regardless of the number of
li's used — if the list was 100 items long, we'd be saving ourselves 198 event listeners, which is enough to make a noticable difference in how your page responds. In a complicated page context, it's easy to see how this technique can dramatically reduce the number of event listeners required and thereby improve the performance of your application.