Passing Objects into addEventListener Instead of Functions

I was reviewing the browser event stack the other day and was reminded of a rarely used feature of addEventListener that allows developers to autobind the execution context object, instead of requiring a call to bind or using a library, that is worth sharing, if you weren’t already aware.

How do it…

Typically, when attaching an event, we write:

var myObj = {
    handleEvent: function (evt) {
        // 'this' will be scoped to the element, instead of myObj.
    }
};
document.getElementById('<MY_ID>').addEventListener(
    'click', myObj.handleEvent);

However, addEventListener also supports passing an object as the second argument, as long as the object defines handleEvent:

var myObj = {
    handleEvent: function (evt) {
        // 'this' will be scoped to myObj.
    }
};
document.getElementById('<MY_ID>').addEventListener('click', myObj);

The event is removed in the same fashion:

document.getElementById('<MY_ID>').removeEventListener('click', myObj);

For a full-fledged implementation, I would do something like this:

var myObj = {
    keyPressEvent: function (evt) {
        // handle key only events
    },
    clickEvent: function (evt) {
        // handle click only events
    },
    handleEvent: function (evt) {
        switch (evt.type) {
            case 'click':
                this.clickEvent(evt);
                break;
            case 'keypress':
                this.keyPressEvent(evt);
                break;
        }
    },
    init: function() {
        var el = document.getElementById('<MY_ID>');
        el.addEventListener('click', myObj);
        el.addEventListener('keypress', myObj);
    }
};
myObj.init();

How it works…

The spec for addEventListener allows developers to pass, as the second argument, either a function or an object with a function named handleEvent attached to it. The rest of the signature is identical between the two implementations. If an object is passed, then the execution context of the callback function will be set to the object, instead of the triggering element, which is usually the desired behavior.

The biggest advantage here is writing less, clearer code that does exactly what you want. It is supported by all modern browsers and has been around since addEventListener was added. Unfortunately, the first modern browser produced by Microsoft was IE9, so if you have to support IE < 9, then you’ll need a polyfill[1].

One other advantage to this style of event management, is the implementation of the event specific callbacks can change or be overwritten without the need to remove and/or reattach event listeners.

References

  1. addEventListener, handleEvent and passing objects - has a decent IE polyfill
  2. An alternative way to addEventListener