Backbone.js Cheat Sheet
A reference for Backbone.js Models, Collections, Views, and Routers for structuring lightweight, event-driven single-page applications.
Model & Collection
Defining a data model and a collection that syncs to a REST endpoint.
var Book = Backbone.Model.extend({ defaults: { title: 'Untitled', read: false },});var Library = Backbone.Collection.extend({ model: Book, url: '/api/books',});var books = new Library();books.fetch(); // GET /api/booksbooks.add({ title: 'Dune' });
View
Binding a Model to the DOM with declarative events.
var BookView = Backbone.View.extend({ tagName: 'li', events: { 'click .toggle-read': 'toggleRead', }, initialize: function () { this.listenTo(this.model, 'change', this.render); }, render: function () { this.$el.html(this.model.get('title')); return this; }, toggleRead: function () { this.model.save({ read: !this.model.get('read') }); },});
Core Concepts
The four pieces that make up a Backbone application.
- Model- represents a single data object, with get()/set(), validation, and REST sync
- Collection- an ordered set of Models, with fetch(), add(), remove(), and Underscore methods
- View- binds a Model/Collection to the DOM; a declarative 'events' hash maps DOM events to handlers
- Router- maps URL fragments (hash or pushState) to handler functions via Backbone.history
- Events mixin- listenTo()/trigger()/on() provide the pub-sub system used throughout Backbone
- sync- the method Backbone calls to persist a Model/Collection, defaulting to REST over AJAX
- Underscore.js- Backbone's one hard dependency, used for its utility functions
Router
Mapping URL fragments to handler functions.
var AppRouter = Backbone.Router.extend({ routes: { '': 'index', 'books/:id': 'showBook', }, index: function () { /* ... */ }, showBook: function (id) { /* ... */ },});new AppRouter();Backbone.history.start(); // start listening for hash/pushState changes
Model Validation & Custom Sync
Overriding validate() to reject invalid saves, and sync() to customize how a Model persists.
var Book = Backbone.Model.extend({ defaults: { title: '', pages: 0 }, validate: function (attrs) { if (!attrs.title) return 'Title is required'; if (attrs.pages < 0) return 'Pages cannot be negative'; },});var book = new Book();book.on('invalid', function (model, error) { console.error('Validation failed:', error);});book.save({ title: '' }); // triggers 'invalid', does NOT call sync/save// customizing the transport (e.g. localStorage instead of REST):Book.prototype.sync = function (method, model, options) { if (method === 'read') { options.success(JSON.parse(localStorage.getItem('book:' + model.id))); return; } return Backbone.sync.apply(this, arguments);};
Collection Sorting & Querying
comparator keeps a collection auto-sorted, and Underscore methods provide rich querying without a manual loop.
var Library = Backbone.Collection.extend({ model: Book, url: '/api/books', comparator: 'title', // or a function(model) returning a sort key});var books = new Library([{ title: 'Zed' }, { title: 'Ada' }]);books.first(); // 'Ada' -- auto re-sorted on addvar unread = books.where({ read: false }); // exact-match filtervar longOnes = books.filter(function (b) { return b.get('pages') > 300;});var total = books.reduce(function (sum, b) { return sum + b.get('pages');}, 0);
Nested Views & Memory-Safe Teardown
Manually tracking and removing child views is necessary since Backbone has no component tree to walk automatically.
var ListView = Backbone.View.extend({ initialize: function () { this.childViews = []; this.listenTo(this.collection, 'add', this.addOne); this.listenTo(this.collection, 'reset', this.render); }, addOne: function (model) { var view = new BookView({ model: model }); this.childViews.push(view); this.$el.append(view.render().el); }, render: function () { this.removeChildren(); this.collection.each(this.addOne, this); return this; }, removeChildren: function () { this.childViews.forEach(function (v) { v.remove(); }); this.childViews = []; }, remove: function () { this.removeChildren(); Backbone.View.prototype.remove.call(this); // unbinds DOM + stopListening },});
Backbone.Events as a Standalone Mixin
The Events module can be mixed into any plain object to build a pub-sub bus independent of Model/View.
var EventBus = _.extend({}, Backbone.Events);EventBus.on('cart:updated', function (total) { console.log('New total:', total);});EventBus.trigger('cart:updated', 42.5);// namespaced events + once():EventBus.once('app:ready', function () { console.log('booted'); });EventBus.trigger('app:ready');EventBus.trigger('app:ready'); // no-op, handler already consumed
Advanced Internals
Lesser-known behaviors that matter once an app grows past a toy example.
- silent option- pass { silent: true } to set()/save() to suppress 'change' events, useful during bulk updates before a manual render
- parse()- override on a Model/Collection to reshape a server response before it's applied to attributes
- idAttribute- override when the server's primary key isn't 'id' (e.g. '_id' for MongoDB-backed APIs)
- stopListening()- removes all listenTo bindings a View registered, called automatically by View#remove()
- Backbone.history.start({ pushState: true })- switches routing from hash fragments to real URLs via the History API
- toJSON()- override to control exactly what a Model sends on save() vs. what it exposes to templates
- wait: true- save/destroy option that waits for server success before updating the model/removing it optimistically
Backbone does not auto-render -- you must explicitly re-render a View when its Model changes, typically with this.listenTo(this.model, 'change', this.render) in initialize, or the DOM will silently go stale after a model update.