DOM 2 Events

The Document Object Model Level 2 defines several interfaces for an event handling model, called DOM 2 Events, that is far superior to the traditional model used by most web developers around the world. In the traditional model, you assign an event handler to an object using the onevent properties. e.g. window.onload = fn;. This has many limitations, with the most annoying being that it only accepts one event handler.

In the past, many attempts have been made to work around these issues, with one of the most widely known being Scott Andrew LePera’s Crossbrowser DOM Scripting: Event Handlers. Recently, Peter-Paul Koch wrote an article entitled addEvent() Considered Harmful. Following this, he launched a competition for someone to rewrite the addEvent() function and write a new removeEvent() function to address the issues with the original.

A few days ago, after I heard about addEvent(), I began work on a new script to address many of the issues with it. The result is beyond anything that was expected for the competition. In fact, I’m pretty sure it’s beyond what most mere mortals even considered possible: I implemented much of the DOM 2 Events interfaces in IE!

What does that mean exactly? Well, it means that you can now use the W3C’s superior DOM2 model across browsers without any of the mess. For example, a script that used to be written like this:

var foo = document.getElementById("foo");
foo.onclick = go;

function go(evt) {
    evt = evt || window.event;
    target = evt.target || evt.srcElement;
    // Handle other cross-browser issues
    doSomething(target);
    ...
}

That can now be reduced to this much more sane method from the DOM2 interfaces:

var foo = document.getElementById("foo");
foo.addEventListener("click", go, false);

function go(evt) {
    doSomething(evt.target);
    ...
}

There’s no need to check for evt || window.event, nor any need to check for evt.target || evt.srcElement. Much of that cross-browser incompatibility mess is taken care of by my script. All that you, the authors, have to do is work with the standard DOM 2 interfaces! You can take a look at the heavily commented script and also my entry for PPK’s competition, which nicely demonstrates the script in action.

The following interfaces, properties and functions are supported from DOM 2 events:

Interface EventTarget
addEventListener
dispatchEvent
removeEventListener
Interface EventListener
handleEvent
Interface Event
PhaseType Constants (CAPTURE_PHASE, AT_TARGET and BUBBLE_PHASE)
bubbles
cancelable
currentTarget
eventPhase
target
timeStamp
type
initEvent() (not supported)
preventDefault()
stopPropagation()

Along with these event interfaces, there are a number of other interfaces I implemented including a fully conforming .getElementsByClassName() function, as defined in the Web Apps 1 for both the Document and Element interfaces, a prototype implementation of DOMTokenString() and many more, all availble in my DOM example script repositiory.

11 thoughts on “DOM 2 Events

  1. In fact, I’m pretty sure it’s beyond what most mere mortals even considered possible: I implemented much of the DOM 2 Events interfaces in IE!

    YOu have one hell of an ego – good for you.

  2. Nice.
    Still, it doesn’t deal with capturing, does it?
    Is it possible?

    Given my (very) limited knowledge, I would do:
    - dont register the real events handlers, but a function that will store the element in a global var
    - so, during the bubble phase along the tree, nothing “really” happens, except we store the event “road” to root
    - then we hit root; we read the list containing the elements, now we may apply (i: length => 0) road[i].allCapturingEvents(), then (i: 0 => length) road[i].allBubblingEvents()
    Of course with proper checks on cancel…

    I got something like that (half-assed) working, but am no JS god :(
    Is this totally stupid?

    Cheers
    - dMp

    Please forgive unclear explanations and rough english…

  3. Double posting, sorry.

    I also ran into that one while developping my own solution:
    With firefox, you can’t register the very same event two times.
    eg:
    x[i].addEventListener(“click”, up, false);
    x[i].addEventListener(“click”, up, false);
    will only add one event.

    Your solution, with Internet Explorer, do register two events.
    (and both are deleted when removing…)

    I’m not sure, but I think the best approach should be not to allow “double” registering…

  4. dMp, I thought about doing something like that to implement capture events in IE, but it seemed rather complex. I might do something like that in the future.

    Identical events listeners aren’t supposed to be registerred twice, that is defined in the DOM 2 spec, so it’s a bug. I thought I had handled it already, but it looks like I forgot to put the it in. Thanks

  5. Another interesting IE bug…
    Considering the following markup:
    ClickMe

    Put some big borders / margin / padding on the three divs.
    Assuming we registered click events on the three divs.

    If you click on div one you won’t fire the click event.
    If you click on div two, you will have only the event on div one.

    Now this markup is working as expected:
    ClickMe

    I have no idea how this could be fixed… (maybe by adding an empty node with display none in any node that register events?)

  6. code mangled…

    div id=”one” div id=”two” div id=”three” ClickMe /div /div /div

    second case: just add empty spans into div one and div two.

  7. dMp, you can’t put markup like that into comments, if you can publish a minimal test case somewhere and link to it, or failing that, e-mailing me, I might be able to do something about it.

  8. Hello Lachlan,
    I was trying to use your script (Well, I think that’s allowed?), but I think I’ve found a bug. There’s a testcase at http://www.hamok.be/test/event.html.

    The problem I encountered is that you can’t use your addEventListener function on nodes created by JS. It works great for nodes already present in the document. This is pretty bad for using it in anything but the simplest scripts.

  9. Jeroen, I’m aware of that issue. I initally had a solution that used a custom document.createElement function to attach the methods before returning, which worked in IE, but it caused serious problems is Safari, so I coudn’t use it.

    I was considering using Object.prototype to attach events to, instead of iterating through all the elements on the load event, but I’ve since found out that doing so can be harmful, so I’m still looking for a solution.

Comments are closed.