-->
Bookmark and Share

The DOM Event Model

Review the W3C DOM2 Event standard recommendation.

Event Listeners

DOM objects can also be registered as event listeners. This feature can be used to assign multiple handlers for a given event. It also allows you to capture events during either one of two phases in the event flow, capture or bubble.

The difference between these two phases will be covered later on in the discussion on event flow. But for now we'll just look at how to register an event listener.

The basic methods and syntax are

node.addEventListener(eventType, function, useCapture);
node.removeEventListener(eventType, function);

where eventType is a predefined event name such as "mouseover" or "click" (the same as the corresponding event attribute but without the preceding "on"), function is the name of the handler function and useCapture is a boolean flag which specifies which phase of the event flow the handler will be called on.

To demonstrate, the previous example could have assigned event handlers for the sample paragraph element with the following:

var el = document.getElementById('sample1');
el.addEventListener("mouseover", highlight, false);
el.addEventListener("mouseout",  normal,    false);

Additional handlers could also be assigned for a given event:

el.addEventListener("mouseover", highlight2, true);
el.addEventListener("mouseover", highlight3, false);

Individual event listeners can be subsequently removed by specifying the same arguments:

el.removeEventListener("mouseover", highlight2, true);
el.removeEventListener("mouseover",  highlight3, false);

Note that you must specify the same useCapture value when removing a listener as when it was added. This is because,

el.addEventListener("mouseover", highlight, true);
el.addEventListener("mouseover", highlight, false);

defines two unique event listeners, calling the same function for the same event on the same element but which activate during different phases.

One advantage of this method is that event listeners can be assigned to any node, even text nodes which you could not normally assign event handlers to as they have no attributes.

Browser Compatibility

Internet Explorer, as of version 6, and Opera, as of version 5, do not support event listeners. IE does provide the attachEvent() and detachEvent methods which give you the ability to assign multiple handlers for a given event (note that it expects the "on" prefix on the event name) and subsequently remove them:

var el = document.getElementById('sample1');
el.attachEvent("onmouseover", highlight);
el.attachEvent("onmouseover", highlight2);
el.attachEvent("onmouseover", highlight3);
el.attachEvent("onmouseout",  normal);

...

el.detachEvent("onmouseover", highlight2);
el.detachEvent("onmouseover", highlight3);

However, this feature does not allow you to specify the event phase, it cannot be used on text nodes and it is not part of the DOM standard.

Event Flow

Before going into event processing, it's helpful to understand event flow in the DOM. HTML documents (and XML or XHTML documents) are hierarchical in nature. Elements and text are nested within other elements. Because of this, when an event occurs on a particular object, it effectively occurs on any containing objects as well.

To illustrate, consider the following HTML:

<div>
<p>Some text in a paragraph element.</p>
<p>Another paragraph element with text.</p>
<p>Yet another paragraph with text and also a
   <a href="blank.html">link</a>.</p>
</div>

If you click on the link defined in this code sample, it will trigger a onclick event on the A tag. But you're also clicking on the paragraph that contains that link, and the DIV that contains that P element and so on up to the document object itself.

Any of the elements in this chain can have an event handler assigned to it to capture the onclick event, regardless of which element it originated at.

Event Bubbling

The DOM event model provides for this using a concept called event bubbling. For example, suppose an onclick event handler were assigned to the DIV tag above. Clicking on the link would fire the event first on the A element, it would then "bubble" up to the containing P element and then up to the DIV where the handler function would be called.

It's possible for the handler to cancel the event, but assuming it doesn't the event would continue bubbling on up to the document root and finally, the browser would follow the default action of loading the link's URL in the window.

Note that the P element could also have had an onclick event handler set, as could any elements above the DIV in the document tree. All of these handlers would be called in turn as the event bubbles up to the document root.

This is known as the bubble phase in the DOM event model. Not all events bubble, for example onfocus and onblur do not. Likewise, not all bubbling events can be canceled, stopping the propagation. You can determine which events bubble and can be canceled either by looking up the documentation for the event or, as we'll see, using the Event object.