Tip - You probably don't need bindAsEventListener()

The Short Version

It's extremely unlikely you want or need to use bindAsEventListener in your code. You almost certainly want bind instead. If you're not using a DOM0 handler you don't have control over, and you're not trying to "burn in" ("curry") additional arguments for a handler that expects them after, rather than before, the event object, you're golden. Just use bind.

The Long Version

When you're using instance methods as event handlers, like this:

$('someId').observe('click', this.clickHandler); // <= WRONG (probably)

…you've probably learned that you need to "bind" the handler to the instance, otherwise "this" will be wrong when the handler is triggered by the event. In the vast, vast majority of cases, you do that with Prototype's bind function, like this:

$('someId').observe('click', this.clickHandler.bind(this));

(See this tip for the details.)

So if that's how you bind an event handler (or "listener"), then why is there this tempting bindAsEventListener function offered by Prototype? When do you want to use it?

Almost never.

There are basically two reasons you might use bindAsEventListener:

1. You're hooking up a DOM0-style event handler ("onclick=", that sort of thing) you don't have control over that wasn't written to be compatible with Internet Explorer, and you want to make it compatible with Internet Explorer.


2. You want to "burn in" (or "curry") additional arguments for the handler that should appear after the event object in the argument list.

Let's deal with #1 first: If you're assigning an event handler via the old "onclick=" style DOM0 stuff, and the handler doesn't already start with

function handler(event)
    // Deal with IE
    event = event || window.event;
    // ...

…then you might use bindAsEventListener. This only applies if you don't have control over the code of the handler. If you do, revise it so you can use Event.observe instead; that's what it's for. Or if you really, really have to make it a DOM0 handler, then just put the line shown at the top of your handler and use bind.

Okay, #2 takes a bit longer to explain: In this case, bindAsEventListener is a very specific solution to a very specific problem, a problem very few people ever have or, if they have it, they solve in different ways.

Let's step back a moment and talk about bind. bind does two things:

  1. Binds the function to a context (a "this" value) — this is the only part of it most people use, most of the time
  2. Binds some initial arguments to the function (like Function#curry) — this gets relatively little use

So, say I have this class:

var UriLikeThing = Class.create({
    set: function(protocol, server, path, query) {
        // ...set the various parts from the params...

…and I want a function bound to a given instance that only allows creating HTTP URIs on a given server (don't ask me why). bind can give me that:

var uri = new UriLikeThing();
var f = uri.set.bind(uri, 'http', 'example.com');

Voila! If you call f(…), it calls uri.set('http', 'example.com', …) with the … being whatever arguments are passed into f(). So:

// => Calls uri.set('http', 'example.com', 'index.html')
f('get.php', 'thingy');
// => Calls uri.set('http', 'example.com', 'get.php', 'thingy')

So what does this have to do with bindAsEventListener? bindAsEventListener is exactly the same as bind except it assumes that the resulting function will only ever be called with one argument, the event object for the event, and it defaults that first argument to window.event if the first argument is falsey (to support Internet Explorer DOM0 handlers; all other handlers [those registered with Event.observe, or DOM0 handlers on just about any other browser] always receive a non-falsey event object anyway).

So what use is it? Well, a highly-specific one, as we said. For it to be of any use at all to you, your event handler would have to:

  1. Expect the event object as the first argument
  2. Have other arguments after event
  3. Expect this to have some specific meaning (unless you pass undefined as the first argument to bindAsEventListener)

So effectively:

var MyCuriousClass = Class.create({
    myCuriousEventHandler: function(event, some, other, args) {
        // ...do something with 'this' and the various args

Then you can set up event handlers like so:

var c = new MyCuriousClass();
$(element).observe('click', c.myCuriousEventHandler.bindAsEventListener(c, 'some', 'other', 'args');

When the element gets clicked, myCuriousEventHandler will be called with the correct this value, the event object as its first argument, and then 'some', 'other', 'args' as its some, other, and args arguments respectively.

Why would you code your event handler that way? Well, you probably wouldn't, but it does offer you the flexibility of having optional additional arguments to your event functions, and then sometimes having the event called without those (via direct bind), but other times passing a bit of extra info as an optional parameter {via bindAsEventListener). There a lots of other ways to do that; bindAsEventListener was created for this specific one.

Like we said. A very specific solution to a very specific problem.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License