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.
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.