Thursday, April 17, 2014

JavaScript methods as event handlers

I've gotten pretty frustrated with JavaScript losing subject state when methods are used as event handlers.  (This might be a problem only in Firefox, I'm not sure.)  Here I'll describe the problem and the workaround I discovered today while teaching Web Programming.

Problem:

Consider the following code inside a method.  (mouse is an HTMLElement)

...
mouse.onclick = this.handleClick;
...

And this definition of the handleClick method (I'm using the prototype.js syntax):

handleClick: function(event) {
    alert(this.someAwesomeProperty);
}

If I test this out (again, in Firefox) I get the error that "this" (used the handleClick method) is undefined.  That's because JavaScript doesn't save the state of the object's method that's getting called.  That object is no longer "associated" with that method.  It remembers where in the code to find that class's handleClick method, but not a reference to the actual instance.

Intermediate step to Solution:

I recently read that nested functions kept references to all local variables declared in the same context they were defined.  To use that, we first have to assign mouse.onclick to use an anonymous function that wraps the handleClick:

...
mouse.onclick = function(event) {
    this.handleClick(event);
}
...

If you try running this, it still won't work.  That's because this wasn't defined in the same scope as the anonymous function definition.  We can fix this by creating a local reference to this ahead of time.

Solution:

...
var self = this;
mouse.onclick = function(event) {
    self.handleClick(event);
}
...