webdev: (Default)
[personal profile] webdev
One of my favorite little-known features of the DOM is the EventListener interface. We all know how to attach an event listener to a DOM element using Element.addEventListener method, which takes three parameters:

  • eventType: a string that indicates the type of event

  • handler: a function to execute when the event happens

  • bubble: whether or not to execute the function during the bubble phase

What’s little known is that the DOM specifies you can use any object as the handler, as long as it implements the EventListener interface. According to the DOM Level 2 standard:

The EventListener interface is the primary method for handling events. Users implement the EventListener interface and register their listener on an EventTarget using the AddEventListener method. The users should also remove their EventListener from its EventTarget after they have completed using the listener.

An EventListener interface is simply a method on the object called handleEvent. Thus, the two event handlers can be used interchangeably:
function handleClickFunction(event) {
  alert(‘The element was clicked!’);

var handleClickObject = {
  handleEvent: function(event) {
    alert(‘The element was clicked!’);

You register an event handler object using Element.addEventListener just like a function:
var myElement = document.getElementById(“targetElement”);
myElement.addEventListener(“click”, handleClickObject, true);

When a click event happens on the target element, handleClickObject.handleEvent will be invoked. Within that method, the this keyword will be a reference to handleClickObject, just like you’d expect.

One of the great things about this is it makes it easy to build a single object containing several event handlers, and then use the EventListener interface to delegate to the appropriate type. For example:
// Create an EventManager “class” that we can use as a base from which
// to instantiate event managers for elements as needed.
var EventManager = {
  handleEvent: function(event) {
    if (this[event.type] != null) {
      this[event.type].call(this, event);
    } else {
      console.log('no event handler for event of type ' + event.type);

// Create an event manager object from our base class, adding in
// methods for click and mousedown (but not mouseup)
var testElEventManager = Object.create(EventManager, {
  click: {
    value: function(event) {
      console.log('click event happened');
  mousedown: {
    value: function(event) {
      console.log('mousedown event happened');

// Bind the new event manager to testEl for the events click, 
// mousedown, and mouseup.
testEl.addEventListener('click', testElEventManager);
testEl.addEventListener('mousedown', testElEventManager);
testEl.addEventListener('mouseup', testElEventManager

In this example I’ve created a base object which implements the EventListener interface. All it does is check to see if a method exists on the object for a given event type, and if it does it calls it, and if it doesn’t it provides an error.

Then I create a new event manager from that base object using Object.create(). You could just as easily have created a constructor function; I prefer this technique because it allows me to add new methods as part of the creation step. In this example, I’m adding methods for click and mousedown events.

Then I bind the new event manager object to my test element for the three events click, mousedown, and mouseup.

When you click on the element, the mousedown-mouseup-click event sequence will fire, and the following output will result on the console:
mousedown event happened
no event handler for event of type mouseup
click event happened

This illustrates using a single object to handle multiple event types--pretty nifty.

Coming up: Using this method to create a single Event Manager object that serves as a one-stop shop for everything event-related: registration, delegation, etc. We can even include some nifty extra features like namespacing.


webdev: (Default)
Jon Reid

October 2013

  12 345
272829 3031