Colin Sullivan

Event Handler Gotcha with Backbone.js

I just fixed a bug in the Backbone.js related portion of my application. The issue was specific enough to Backbone.js that I'd like to document it here as a warning to tread carefully in complex-applications written in JavaScript land.

Has one of your event callbacks seemingly stopped being called when it should be? Perhaps it is a related issue.

the setup

Here was the basic structure of the problematic part of my code:

var MyAwesomeView = Backbone.View.extend({
initialize: function () {
this.model.on("change:theProperty", this.render, this);
},
 
render: function () {

// ...
 
}
});
 
MyAwesomeController.prototype = Controller.extend({
when_something_is_added: function () {

// ...
 
// start watching for when the property changes!
this.model.on("change:theProperty", this.when_property_changes, this);

// ...
 
},
when_something_is_removed: function () {

// ...
 
// stop watching for when the property changes
this.model.off("change:theProperty", this.when_property_changes, this);
 
// ...
 
},
when_property_changes: function () {

// ...
 
}
};

JavaScript

So a pretty simple MVC architecture (model not shown, but assume that this.model is the same instance in both of the classes above). The view MyAwesomeView will render when theProperty of the model changes, and the controller MyAwesomeController only sometimes wants to watch theProperty on the same model.

the change

But then I decided that I didn't want this functionality in my controller anymore, so I did this:

MyAwesomeController.prototype = Controller.extend({
when_something_is_added: function () {

// ...
 
// start watching for when the property changes!
this.model.on("change:theProperty", this.when_property_changes, this);

// ...
 
},
when_something_is_removed: function () {

// ...
 
// stop watching for when the property changes
this.model.off("change:theProperty", this.when_property_changes, this);
 
// ...
 
},
/*when_property_changes: function () {

// ...
 
}*/
};

JavaScript

the bug

That was where I introduced a bug. Now in MyAwesomeView, the render method was not being called!

Take a look at how that change affects the other event handler calls in the controller. In particular, the call to this.model.off now means something entirely different because

// stop watching for when the property changes
this.model.off("change:theProperty", this.when_property_changes, this);

JavaScript

is equivalent to

this.model.off("change:theProperty", undefined, this);

JavaScript

which Backbone.js treats as:

this.model.off("change:theProperty");

JavaScript

which removes all event handlers from the model, including the one that the view had setup to render itself.

yup.

A good reminder of the limited options for JavaScript development tools and that we have to be careful when dealing with large projects! When removing symbols, take the time to check where they are used!