Event aggregation with Backbone
This is the sixth post in my blog series on Backbone.js. If you haven’t had a chance yet, make sure to catch up on the first 5:
- Hey, check out my Backbone
- Aligning my Backbone
- Backbone Routers Are Configuration
- Grokking Backbone Views
- Async Template Loading with Backbone
In my second post I talked about how I employ the MVP design pattern to keep components of my JavaScript apps nicely decoupled. Interestingly, since that post, there have been some rumblings on the interwebs calling this pattern ‘MOVE’. I think you’ll see it popping up more and more as it gains momentum.
In my first post, I also mentioned that when you look at Backbone through an “MVC lense”, initially people often make a few incorrect assumptions on how the app should work. This is often based on their understanding of how a server-side MVC app functions. It certainly was in my case. In this post I’m going to cover how this approach differs from the common understanding of server-side MVC.
Getting Pub/Sub

One piece of knowledge hit me last fall as I was writing the Facebook authentication app (in Backbone/CoffeeScript) for the latest version of CentralAZ.com. Here it is: JavaScript apps written on the client are not stateless. If you’ve written lots of client apps in your career, then this probably isn’t a huge surprise to you, but this little tidbit of knowledge totally blew my mind. My focus had been on the server for so long, that I projected a lot of what I knew about ASP.NET MVC and Rails onto Backbone. This post by Derek Bailey really drove that point home for me. In a Backbone application, the model is a representation of the current application state.
mind === 'blown' > true
In Backbone, the preferred method of cross-communication between app components or modules is to use the Observer pattern, also commonly referred to as “pub/sub”. In Backbone, you get a very nice way implementing this pattern via extending Backbone.Events. This allows different components of an app to send messages or listen for messages being broadcast by an event aggrigator without having to know where those events are coming from.
How does that work?
To illustrate, we’ll assume each JS module lives in its own file and that the app is composed when the page loads via AMD (Asyncronous Module Definition) in Require.js. It’s not important to fully grok AMD to understand how the following code samples work together, the important thing to understand, though, is that each of these JS snippets represent separate JS files. They’re fully encapsulated and know nothing of each other, beyond the dependencies they request in the first parameter of the define() function call.
// Define a module to return an event aggrigator object extended from Backbone.Events.
// Let's call this events.js.
define(['underscore', 'backbone'], function (_, Backbone) {
return _.extend({}, Backbone.Events);
});
Let’s pretend we have an app that allows a user to authenticate and view their own personal information. In this sample app, we’ll be listening for 2 different events. We want to listen for an event that signifies that a user intends to log out of their account. But we also want to know when the user has actually been logged out by the server. In Backbone apps, it’s considered good practice to namespace your events by object or model type. An event name can be any string value, but in order to keep things organized and easy to understand, we’ll use this convention:
events.trigger('object:property');
// or
events.trigger('object:action');
OK, so now that we’ve got our event aggregation object, we’ll listen for the user:loggedOut event in the initialize method of our router. When a user clicks on a “logout” button, the user should be redirected to the home page once the server successfully logs them out. We’ll take a pessmistic approach to this event, meaning that we’ll wait to make sure “logout” actually happened on the server before we redirect.
// Defining a router module, called router.js
define(['backbone', 'events', 'presenter'], function (Backbone, events, Presenter) {
var router = Backbone.Router.extend({
routes: {
'': 'index',
'myprofile': 'userProfile'
},
initialize: function (options) {
// Wiring up the presenter just like we did in a previous post...
this.presenter = new Presenter(options);
// _.bindAll is important here, because `this` will not be the current
// instance of our router when it the events bound below get triggered.
_.bindAll(this);
// Here's the magic that binds a function to the `user:loggedOut` event
events.on('user:loggedOut', this.onLogout);
},
// Here's our event handler. It accepts a user model object, but we're not
// going to use it here...
onLogout: function (user) {
// Call Backbone.Router.navigate here to tell our router to update the
// URL and log browser history, sending the user to the home page. The
// empty string in this call corresponds to the empty string in the
// routes declaration above.
this.navigate('', true);
},
// Route handler definitions that get bound based on routes defined above
index: function () {
this.presenter.showIndex();
},
userProfile: function () {
this.presenter.showUserProfile();
}
});
return router;
});
Additionally, we’ll have a view called authenticationView.js that listens for the user:loggedOut as well, that will fire when the user is successfully logged out by the server.
// Defining a authentication view module called authenticationView.js
define(['backbone', 'events', 'templateManager'],
function (Backbone, events, TemplateManager) {
var view = Backbone.View.extend({
template: 'userAuthentication',
className: 'user-authentication',
initialize: function (options) {
this.model = options.model;
_.bindAll(this);
// When the user logs out, we just want to re-render this view
events.on('user:loggedOut', this.render);
},
// Nothing extra special going on in our view's render method. Our template will
// check the model's `isAuthenticated` flag to see if the user is currently
// logged in.
render: function () {
var that = this;
TemplateManager.get(this.template, function (tmp) {
var html = tmp(that.model.toJSON());
that.$el.html(html);
that.rendering();
});
return this;
},
// In a previous post I covered having your views clean up after
// themselves to avoid memory leaks. Here's a good example of this
// in practice. In `onClose`, we'll unsubscribe from `user:loggedOut`
onClose: function () {
events.off('user:loggedOut');
}
});
return view;
});
Here’s what our corresponding Handlebars client-side template would look like. We’ll call it userAuthentication.html.
{{#if isAuthenticated}}
<a href="#">Howdy {{name}}!</a>
{{else}}
<a href="#">Log In</a>
{{/if}}
We’ll also have a second view that has a “Log Out” button that will fire the user:loggingOut event to get things kicked off.
// Defining our userProfile.js module.
define(['backbone', 'events', 'templateManager'],
function (Backbone, events, TemplateManager) {
var view = Backbone.View.extend({
template: 'userProfile',
className: 'user-profile',
events: {
'click #log-out', 'logoutClicked'
},
initialize: function (options) {
this.model = options.model;
_.bindAll(this);
},
render: function () {
var that = this;
TemplateManager.get(this.template, function (tmp) {
var html = tmp(that.model.toJSON());
that.$el.html(html);
that.rendering();
});
return this;
},
logoutClicked: function () {
// Fire the `user:loggingOut` event to kick things off. Make sure to pass
// along a reference of the current user.
events.trigger('user:loggingOut', this.model);
return false;
}
});
return view;
});
You might be asking yourself, “That’s great, but how does the user actually get logged out?”
Great question. We’ll just wire up another listener on the presenter to tell the model to log itself out.
// For posterity, here's what our presenter.js would look like.
define(['events', 'userModel' 'indexView', 'userProfileView'],
function (events, UserModel, IndexView, UserProfileView) {
var Presenter = function (options) {
this.model = options.model || new UserModel();
_.bindAll(this);
// We'll set up a handler here to listen for `user:loggingOut`
events.on('user:loggingOut', this.onLogout);
};
Presenter.prototype.showView = function (view) {
if (this.currentView) {
this.currentView.close();
}
this.currentView = view;
$('#container').append(this.currentView.render().$el);
};
Presenter.prototype.showIndex = function () {
var view = new IndexView({ model: this.model });
this.showView(view);
};
Presenter.prototype.showUserProfile = function () {
var view = new UserProfileView({ model: this.model });
this.showView(view);
};
// Here's our handler for `user:loggingOut`. We'll have the user model call logout
// on itself.
Presenter.prototype.onLogout = function (user) {
var promise = user.logout();
// `user.logout` returns a jQuery deferred, so we can bind a handler to trigger
// the `user:loggedOut` event when the ajax call completes successfully.
promise.done(function () {
events.trigger('user:loggedOut', user);
});
};
return Presenter;
});
Finally, to complete the story, we’ll wire up our user model so it knows how to to log itself out.
// Defining a module for our user model called user.js
define(['backbone', 'events'], function (Backbone, events) {
var model = Backbone.Model.extend({
initialize: function (options) {
_.bindAll(this);
},
logout: function () {
var that = this,
promise = $.trafficCop({
type: 'POST',
url: '/user/logout',
data: this.toJSON()
});
// Bind a callback to our promise to set the `isAuthenticated` flag
// to `false` when logout completes successfully.
promise.done(function () {
that.set({ isAuthenticated: false }, { silent: true });
});
return promise;
}
});
return model;
});
But why not just use jQuery’s built in event pool?
It’s true that jQuery has its own version of Backbone.Events that looks the same, and is implemented, in much the same way. The Backbone team, I believe, decided to roll their own version for two good reasons:
- If I understand correctly, when Backbone was first being written, jQuery’s event pooling employed a DOM-based eventing system (e.g. -
document.addEventListener, etc). Since then, jQuery has moved to an object-based eventing system similar to Bacbkone’s. - In order to keep the dependency tree light, Backbone’s only dependency is Underscore. There’s not a hard dependency on jQuery (nor should there be). Using jQuery’s eventing system would require a hard dependency on jQuery.
What’s with _.bindAll being called everywhere?
A lot of people new to Backbone may not be too cozy with Underscore (yet). Basically, calling _.bindAll(this) will ensure that all methods of the object passed in will have the correct context of this bound to its calling context. Doing this basically guarantees that this will represent the current object in scope, rather than window, a DOM element, or some other less predictable thing.
That’s what I’ve got for now. Does your mind hurt yet? When you recover, do you think you might use this approach in your apps? Let me know if in the comments below.

