Uniform Event Model - Brief Introduction to Event handling
What are events and event handlers?
An event handler is a piece of code designated to be executed when a certain event occurs. An event can be a user input such as clicking the mouse, pressing a key or a user interface event such as a page finising loading or moving the focus from one element to another.
Normally you will see code such as <div onclick="doClick(event);">. This
means that when you click the div element the function doClick is executed. We
refer to the doClick function as the event handler or sometimes the event listener.
Once the doClick function starts executing it will get access to the special event object.
The event object holds information about what went on at the time the event occured. In this example the event object will tell us the
position of the mouse cursor, which button was pressed and a lot of other things. The event handler can
then take action based on the position of the mouse cursor for instance.
Problems arise when we have to execute our code in different browsers. JavaScript have always been supported in different ways in different browsers and never the way W3C intended. What you see working in Internet Explorer (IE) may not work in FireFox (FF) or the other way around. This is especially true for how events are supported. UEM is an effort to make any browser work as the W3C DOM 2 (and later 3) Recommendations. In other words to make IE work as FF when handling events. This does not imply that FF (ie. Mozilla) complies 100% with W3C but it comes a lot closer than IE.
With UEM you don't have to branch your event handler code to accomodate for various browsers. If you write your code according to the W3C recommendations UEM will attempt to execute that code the same way in all browsers.
How to assign event handlers
There are 3 different ways to assign an event handler
-
As an attribute of a HTML tag as in
<div id="testDiv" onclick="doClick(event);"> -
As a property of an object as in
document.getElementById('testDiv').onclick = doClick; - With the EventListerner Interface as in
document.getElementById('testDiv').addEventListener("click", doClick, false)
UEM will support any of these methods (including attribute assignments using innerHTML)
The first way of assigning event handlers lets you define mulitple parameters to be passed to the
event handler function. If you want FF to be able to use the event object you must pass this as one of the arguments to your
event handler. IE does not work like that. When IE execute an event handler the event object is instead available to the event
handler as the property event of the global window object.
This usually leads to code like the following
1 // We want to find the element which triggered the event 2 // First argument e is the event object passed from the 3 // inline definition 4 function doClick(e) { 5 // In IE 6 if (e.srcElement) 7 return e.srcElement; 8 // As W3C specifes (FF) 9 else 10 return e.target; 11 }
The first thing to notice is that if we had named the first parameter to the event handler something else than
event IE would cough up an error for this example. Because event is a global variable
IE can pass it to the event handler function. Second is the branching of the code. The event.target
W3C property is called event.srcElement in IE so we have to check for each browser. This quickly becomes
tedious and this is exactly what UEM will avoid.
One feature which is unique to assigning event handlers as attributes is the ability to pass extra arguments to the
event handler. For instance you might define a tag <div onclick="doClick(event,this);">.
This would pass the event object along with a reference to the div element itself.
Using the keyword 'this' has a different meaning when the handler is registered as an attribute. It then becomes
a reference to the global window object. If the event handler is assigned as a property or with the addEventListener method
then 'this' is a reference to the element which triggered the event. Example 1 shows the first case while example 2
shows the later.
1 // Ex. 1 - The meaning of 'this' when 2 // registered as an attribute 3 // Define inline handler 4 <div id=\"testDiv\" onclick=\"test(event)\"> 5 A div for testing 6 </div> 7 // Define event handler 8 function test(e) { 9 // 'this' refers to the window object 10 // the alert will output 'null' 11 alert(this.id) 12 }
1 // Ex. 2 - The meaning of 'this' when 2 // registered as a property or with 3 // addEventListener 4 <div id=\"testDiv\"> 5 A div for testing 6 </div> 7 // Register event handler as property assignment 8 document.getElementById('testDiv').onclick = test; 9 // Define event handler 10 function test(e) { 11 // 'this' refers to the div element 12 // the alert will output 'testDiv' 13 alert(this.id) 14 }
This above is also true for any event handler defined as an attribute using the innerHTML
property.
The second way of assigning an event handler is as a property of an element. This is usually done as shown in ex. 2. This way it is not possible to specify which paramters should be passed to the event handler. As before this also leads to branching code just in a slightly different way
1 // We want to find the element which triggered the event 2 // First argument e is the event object passed in FF. 3 // IE recieves no such argument. 4 function doClick(e) { 5 // If IE 6 if (!e) 7 e.target = event.srcElement; 8 // As WC specifes (FF) 9 return e.target; 10 }
Again UEM will again make sure that you don't need to branch your code. Assigning an event handler this way while using
UEM is the equivalent of [div element].addEventListener("click",doClick,false).
The third way is using the EventListener Interface. If you have never read the W3C specifications or have always coded for IE then you are probably not familiar with these terms. IE does provide some methods similiar to the ones defined in the EventListerner interface which you might have heard of.
| W3C | IE |
addEventListener(type,handler,capture) | attachEvent(type,handler) |
removeEventListener(type,handler,capture) | removeEvent(type,handler) |
dispatchEvent(event) | fireEvent(event) |
If you already know the IE methods then rest assure that the W3C is not much different - they just add functionality. The major difference is the capture argument. This argument specifies when the event handler should be invoked. W3C define three seperate phases whenever an event occurs. Note that not all events are subject to all phases.
DOM 3 Event Flow (Copyright W3C)
The picture describes what happends when an event is triggered on the td element marked with blue color. First any direct parent of the td element from the document top (the body element) to the target (the td element) has a chance of handling the event. This is the capturing phase denoted by the red arrows. If the capture argument to addEventListener is true then the event handler is registered for execution in the capturing phase. Following the capture phase is the target phase depicted in blue. The only event handlers which can execute now is the ones registered on the td element. Following the target phase is the bubbling phase in green which is just the opposite of the capturing phase. Any event handler registered with capture as false is executed in this phase. IE does only support the bubbling phase natively. UEM adds support for the entire W3C event flown.
If you never encountered event propagation (as this is called) before you might be a little intimidated. Fear not - you can still make
use of UEM. If you are used to the IE way then just always call addEventListener with capture as false. UEM exposes a pseudo EventListener
interface to the HTMLElement class. This means that the addEventListener, removeEventListener and dispatchEvent
methods are available for all elements in your code thus you may register an event handler on a element like so
1 // Register an event listener. 2 var elm = document.getElementById('testDiv'); 3 // Register a function doClick for the onclick event 4 // in the bubbling phase 5 elm.addEventListener(\"click\",doClick,false);
When writing the event handler you don't have to worry about different types of browsers
1 // We want to find the element which triggered the event 2 // Don't branch code - works the same way in all browsers 3 function doClick(e) { 4 return e.target; 5 }
UEM makes sure that the event handler is passed a suitable event object which holds the properties and methods defined by W3C. Also note that this way you may have multiple event handlers for any kind of event - a huge advantage over the previous methods of assignment.
Summary
Any event handlers which you have registered as attributes in your code or using the innerHTML property is converted to
a single event handler function registered for the bubbling phase for that type of event.
Any event handler defined as a property of an element is converted to a single event handler function registered for the bubbling
phase for that type of event.
Events defined with the attachEvent method is ignored. The attachEvent and related methods are IE only and defies the
purpose of writing uniform code.
