webdev: (Default)
jQuery does a great job of providing a normalized event model across all browsers. It’s my go-to library for that particular task, plus it has several other useful features. One of the great features jQuery has for its event system is namespacing. You can namespace your event types as you attach, detach, and call them. For example:
// Attach a simple event handler to the element
$(“#targetEl”).on(“click”, function(event) {
  console.log(‘A click event happened!’);
});

// Now attach a namespaced event handler to the element
$(‘#targetEl’).on(‘click.plugin’, function(event) {
  console.log(‘A click.plugin event happened!’);
});

Now, when you click on the target element, both event handlers will fire. If you manually trigger a click event you can add the namespace to it:
$(‘#targetEl’).trigger(‘click.plugin’);

This will trigger only the click.plugin event handler. This gives you an easy way of segregating your event handlers, and is particularly useful with custom events.

Event namespacing is a great feature, and I decided to think about how I might implement it from scratch, just as an exercise. The reason jQuery has namespaced events is because it has its own event handling system, so I started to think about what it would take to write a simple event manager that would provide a namespacing feature.

So here’s a first stab at a general event manager. The goal here isn’t to produce production-quality code, but rather to explore the desired features and get some code up that implements them, and if we like the direction we can later create something that’s more structured.

Long post is best post! Click to continue... )
webdev: (Default)
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.

Profile

webdev: (Default)
Jon Reid

October 2013

S M T W T F S
  12 345
6789101112
13141516171819
20212223242526
272829 3031  

Links

Syndicate

RSS Atom