Complete Backbone.js Cheat Sheet: Models, Views, Collections & More

Introduction: What is Backbone.js?

Backbone.js is a lightweight JavaScript library that provides structure to web applications by offering models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.

Why Backbone.js Matters:

  • Provides structure to JavaScript applications
  • Simplifies data management with Model-View architecture
  • Facilitates synchronization between frontend and backend
  • Promotes organized code with separation of concerns
  • Reduces boilerplate code for common web development patterns
  • Lightweight (only ~7.6kb minified and gzipped)

Core Concepts and Components

1. Models

Models are the heart of any Backbone application, containing the interactive data and logic around it.

// Creating a Model
var Person = Backbone.Model.extend({
  defaults: {
    name: 'Unnamed Person',
    age: 0
  },
  initialize: function() {
    console.log("Model initialized");
  },
  validate: function(attrs) {
    if (attrs.age < 0) {
      return "Age must be positive";
    }
  }
});

// Instantiating a model
var person = new Person({
  name: "John Doe",
  age: 30
});

2. Collections

Collections are ordered sets of models with helper functions for sorting, filtering, and more.

// Creating a Collection
var PeopleCollection = Backbone.Collection.extend({
  model: Person,
  url: '/api/people',
  
  // Custom methods
  adults: function() {
    return this.filter(function(person) {
      return person.get('age') >= 18;
    });
  }
});

// Instantiating a collection
var people = new PeopleCollection();

3. Views

Views handle the visual representation of models and user interaction.

// Creating a View
var PersonView = Backbone.View.extend({
  tagName: 'div',
  className: 'person-container',
  
  events: {
    'click .delete': 'removePerson'
  },
  
  initialize: function() {
    this.listenTo(this.model, 'change', this.render);
  },
  
  render: function() {
    var template = _.template($('#person-template').html());
    this.$el.html(template(this.model.toJSON()));
    return this;
  },
  
  removePerson: function() {
    this.model.destroy();
    this.remove();
  }
});

4. Router

Routers map URLs to functions for client-side page navigation.

// Creating a Router
var AppRouter = Backbone.Router.extend({
  routes: {
    "": "home",
    "people": "showPeople",
    "people/:id": "personDetails"
  },
  
  home: function() {
    console.log("Home route");
  },
  
  showPeople: function() {
    console.log("People route");
  },
  
  personDetails: function(id) {
    console.log("Person details for: " + id);
  }
});

// Initialize router
var router = new AppRouter();
Backbone.history.start();

5. Events

Backbone has a built-in events system for custom events.

// Using events
var object = {};
_.extend(object, Backbone.Events);

// Bind an event
object.on("alert", function(msg) {
  alert("Triggered " + msg);
});

// Trigger an event
object.trigger("alert", "an event");

Step-by-Step: Building a Backbone.js Application

Step 1: Set up dependencies

<!-- Dependencies -->
<script src="jquery.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>

Step 2: Create models and collections

// Define your data structure
var Task = Backbone.Model.extend({
  defaults: {
    title: '',
    completed: false
  },
  toggle: function() {
    this.set('completed', !this.get('completed'));
  }
});

var TaskList = Backbone.Collection.extend({
  model: Task,
  url: '/tasks'
});

var tasks = new TaskList();

Step 3: Create views

// View for a single task
var TaskView = Backbone.View.extend({
  tagName: 'li',
  template: _.template($('#task-template').html()),
  
  events: {
    'click .toggle': 'toggleCompleted',
    'click .delete': 'removeTask'
  },
  
  initialize: function() {
    this.listenTo(this.model, 'change', this.render);
    this.listenTo(this.model, 'destroy', this.remove);
  },
  
  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    return this;
  },
  
  toggleCompleted: function() {
    this.model.toggle();
  },
  
  removeTask: function() {
    this.model.destroy();
  }
});

Step 4: Create app view to manage the application

var AppView = Backbone.View.extend({
  el: '#todo-app',
  
  events: {
    'submit #new-task': 'createTask'
  },
  
  initialize: function() {
    this.input = this.$('#new-task-input');
    this.listenTo(tasks, 'add', this.addOne);
    this.listenTo(tasks, 'reset', this.addAll);
    
    tasks.fetch();
  },
  
  addOne: function(task) {
    var view = new TaskView({model: task});
    this.$('#task-list').append(view.render().el);
  },
  
  addAll: function() {
    this.$('#task-list').html('');
    tasks.each(this.addOne, this);
  },
  
  createTask: function(e) {
    e.preventDefault();
    tasks.create({title: this.input.val().trim()});
    this.input.val('');
  }
});

// Start the app
new AppView();

Step 5: Set up the router

var TodoRouter = Backbone.Router.extend({
  routes: {
    '': 'home',
    'completed': 'showCompleted',
    'active': 'showActive'
  },
  
  home: function() {
    tasks.fetch();
  },
  
  showCompleted: function() {
    tasks.fetch({data: {completed: true}});
  },
  
  showActive: function() {
    tasks.fetch({data: {completed: false}});
  }
});

var router = new TodoRouter();
Backbone.history.start();

Key Methods by Component

Model Methods

MethodPurposeExample
get(attr)Get attribute valuemodel.get('name')
set(attrs, [options])Set attribute valuesmodel.set({name: 'John'})
has(attr)Check if attribute existsmodel.has('name')
unset(attr, [options])Remove attributemodel.unset('name')
clear([options])Remove all attributesmodel.clear()
save([attrs], [options])Save model to servermodel.save()
destroy([options])Delete model from servermodel.destroy()
toJSON()Return JSON representationmodel.toJSON()
validate(attrs)Validate model attributesCustom implementation

Collection Methods

MethodPurposeExample
add(models, [options])Add models to collectioncollection.add(model)
remove(models, [options])Remove models from collectioncollection.remove(model)
reset(models, [options])Replace all modelscollection.reset([])
get(id)Get model by idcollection.get(5)
at(index)Get model at indexcollection.at(0)
push(model, [options])Add model to endcollection.push(model)
pop([options])Remove and return last modelcollection.pop()
fetch([options])Fetch collection from servercollection.fetch()
create(attrs, [options])Create and add new modelcollection.create({title: 'New'})

View Methods

MethodPurposeExample
$(selector)Scoped jQuery selectorview.$('.item')
render()Render the viewCustom implementation
remove()Remove view from DOMview.remove()
delegateEvents([events])Bind events to DOMview.delegateEvents()
undelegateEvents()Unbind events from DOMview.undelegateEvents()
setElement(element)Change the view’s elementview.setElement('#new-el')

Router Methods

MethodPurposeExample
navigate(fragment, [options])Update URLrouter.navigate('help', {trigger: true})
execute(callback, args)Execute route callbackCustom implementation

Framework Comparison: Backbone.js vs. Other Frameworks

FeatureBackbone.jsAngularReactVue.js
Size~7.6kb~30kb+~40kb+~10kb
Learning CurveModerateSteepModerateGentle
Data BindingManualTwo-wayOne-wayTwo-way
StructureMV*MVWComponent-basedMVVM
DOM ManipulationDirect (jQuery)DirectivesVirtual DOMVirtual DOM
DependenciesUnderscore, jQueryNoneNoneNone
TemplatingFlexible (any engine)Built-inJSXVue templates
RoutingBuilt-inngRoute/UI-RouterReact RouterVue Router
Server RenderingCustomAngular UniversalNext.jsNuxt.js
Ideal Use CaseSmall-medium appsEnterprise appsUI-intensive appsProgressive apps

Event Handling in Backbone

Model Events

// Listening to model events
var model = new Backbone.Model();

model.on('change', function() {
  console.log('Model changed');
});

model.on('change:name', function(model, value) {
  console.log('Name changed to ' + value);
});

// Trigger event
model.set('name', 'New Name');

View Events Declaration

var View = Backbone.View.extend({
  events: {
    'click .button': 'handleClick',
    'submit form': 'handleSubmit',
    'change .input': 'handleChange',
    'keyup .search': 'handleSearch',
    'mouseenter .hover': 'handleHover'
  },
  
  handleClick: function(e) {
    // Handle click
  }
  // Other handlers...
});

Common Challenges and Solutions

ChallengeSolution
Memory LeaksUse listenTo() instead of on() for views, and call remove() to clean up views
Nested ViewsImplement a parent-child view system with proper cleanup methods
Deep Model NestingUse libraries like Backbone.DeepModel or implement custom getter/setter methods
Complex UI UpdatesConsider using templating engines like Handlebars or Mustache
Server SynchronizationImplement proper error handling in sync methods and use wait: true for optimistic updates
Route ManagementCreate a central route management system or use Marionette for application structure
Form HandlingUse plugins like Backbone.Syphon or implement form serialization methods
Data ValidationExtend the default validate() method and use events for validation errors

Best Practices and Tips

Model/Collection Best Practices

  • Use the defaults property for all expected attributes
  • Implement proper validation with validate method
  • Avoid direct manipulation of the attributes object
  • Use parse to transform server responses
  • Keep business logic in models, not views
var Person = Backbone.Model.extend({
  defaults: {
    name: '',
    email: '',
    phone: ''
  },
  
  validate: function(attrs) {
    if (!attrs.name) return "Name is required";
    if (!/.+@.+\..+/.test(attrs.email)) return "Email is invalid";
  },
  
  parse: function(response) {
    // Transform if needed
    if (response.fullName) {
      response.name = response.fullName;
      delete response.fullName;
    }
    return response;
  }
});

View Best Practices

  • Use listenTo instead of on for event binding
  • Implement proper cleanup in remove method
  • Keep DOM manipulation in the render method
  • Cache jQuery selectors for performance
  • Use event delegation with the events hash
var DetailView = Backbone.View.extend({
  initialize: function() {
    // Use listenTo instead of this.model.on
    this.listenTo(this.model, 'change', this.render);
    this.listenTo(this.model, 'destroy', this.remove);
  },
  
  remove: function() {
    // Clean up any event bindings to prevent memory leaks
    this.undelegateEvents();
    this.stopListening();
    Backbone.View.prototype.remove.call(this);
  }
});

Application Structure Best Practices

  • Organize files by feature, not by type
  • Use AMD/CommonJS modules for code organization
  • Initialize models before dependent views
  • Implement a mediator pattern for component communication
  • Use namespaces to avoid global variables
// Example file structure
/app
  /models
    TaskModel.js
  /collections
    TaskCollection.js
  /views
    TaskView.js
    AppView.js
  /routers
    AppRouter.js
  /templates
    task.html
    app.html
  app.js

Performance Tips

  • Batch DOM updates with document fragments
  • Use reset instead of multiple add calls for collections
  • Throttle rapid events like scroll and resize
  • Implement data pagination for large collections
  • Cache templates for reuse
// Batching DOM updates
addAll: function() {
  var fragment = document.createDocumentFragment();
  this.collection.each(function(model) {
    var view = new ItemView({model: model});
    fragment.appendChild(view.render().el);
  });
  this.$('#item-list').html(fragment);
}

Advanced Patterns

Composite Views

Managing parent-child relationships between views:

var ParentView = Backbone.View.extend({
  initialize: function() {
    this.childViews = [];
  },
  
  render: function() {
    this.$el.html(this.template());
    
    // Render child views
    this.collection.each(function(model) {
      var childView = new ChildView({model: model});
      this.$('.children-container').append(childView.render().el);
      this.childViews.push(childView);
    }, this);
    
    return this;
  },
  
  remove: function() {
    // Remove all child views first
    _.invoke(this.childViews, 'remove');
    Backbone.View.prototype.remove.call(this);
  }
});

Model-View Binding Patterns

var BindingView = Backbone.View.extend({
  initialize: function() {
    this.render();
    
    // Update specific elements when model changes
    this.listenTo(this.model, 'change:name', this.updateName);
    this.listenTo(this.model, 'change:email', this.updateEmail);
  },
  
  updateName: function() {
    this.$('.name').text(this.model.get('name'));
  },
  
  updateEmail: function() {
    this.$('.email').text(this.model.get('email'));
  }
});

Extensions and Plugins

PluginPurposeURL
Backbone.MarionetteApplication architecture, composite viewsmarionettejs.com
Backbone.SyphonForm data serializationgithub.com/marionettejs/backbone.syphon
Backbone-relationalModel relationshipsgithub.com/PaulUithol/Backbone-relational
Backbone.localStorageLocal storage adaptergithub.com/jeromegn/Backbone.localStorage
Backbone.ValidationModel validationgithub.com/thedersen/backbone.validation
Backbone.PaginatorPagination for collectionsgithub.com/backbone-paginator/backbone.paginator
Backbone.InterceptIntercept and modify syncsgithub.com/lookout/backbone.intercept
Backbone.ViewOptionsSimplify view optionsgithub.com/chalbert/Backbone-ViewOptions

Resources for Further Learning

Books

  • “Developing Backbone.js Applications” by Addy Osmani
  • “Backbone.js Patterns and Best Practices” by Swarnendu De
  • “Backbone.js Cookbook” by Vadim Mirgorod

Websites & Tutorials

Communities

Example Applications

Quick Reference: Backbone.js API Overview

Backbone

  • Backbone.noConflict() – Return control of “Backbone” to original library
  • Backbone.sync(method, model, [options]) – Override to change persistence behavior
  • Backbone.$ – Reference to jQuery or compatible library
  • Backbone.emulateHTTP – Emulate HTTP for older servers
  • Backbone.emulateJSON – Emulate JSON for older servers

Backbone.Events

  • on(event, callback, [context]) – Bind an event
  • off([event], [callback], [context]) – Unbind events
  • trigger(event, [*args]) – Trigger callbacks for event
  • listenTo(obj, event, callback) – Listen to event on another object
  • stopListening([obj], [event], [callback]) – Stop listening

Remember that Backbone.js is a library that gives structure to your JavaScript applications, not a framework that enforces specific patterns. This flexibility allows you to adapt it to your needs but requires discipline to maintain a well-structured application.

Scroll to Top