Backbone gives structure to JavaScript applications by providing models with key-value binding, collections with rich enumerable functions, views with declarative callbacks, and connects to your existing webapp over a RESTful JSON interface.
The project is hosted on GitHub, and the annotated source code is available, as well as an online test suite.
Backbone is an open-source component of DocumentCloud.
| Development Version (0.1.0) | 22kb, Uncompressed with Comments |
| Production Version (0.1.0) | 2kb, Packed and Gzipped |
Backbone's only hard dependency is Underscore.js. For RESTful persistence, and DOM manipulation with Backbone.View, it's highly recommended to include jQuery, and json2.js (which you probably already have).
The core idea behind Backbone is to avoid tying your data to the DOM. It's too easy to create JavaScript applications that end up as tangled piles of jQuery selectors and callbacks, all trying frantically to keep data in sync between the UI, your JavaScript logic, and the database on your server. For rich client-side applications, a more structured approach is helpful.
With Backbone, you represent your data as Models, which can be created, validated, destroyed, and saved to the server. Whenever a UI action causes an attribute of a model to change, the model triggers a change event, and all the Views that are displaying the model's data are notified, causing them to re-render. You don't have to write the glue code that looks into the DOM to find an element with a specific id, and update the HTML contents — when the model changes, the views simply update themselves.
How is this different than SproutCore or Cappuccino?
This question is frequently asked, and all three projects apply general Model-View-Controller principles to JavaScript applications. However, there isn't much basis for comparsion. SproutCore and Cappuccino provide rich UI widgets, vast core libraries, and determine the structure of your HTML for you. Loading the "Hello World" of SproutCore includes 2.5 megabytes of JavaScript on the page; the "Hello World" of Cappuccino includes 1.7 megabytes of JS and images. Backbone is a 2 kilobyte include that provides the core concepts of models, events (key-value observing), collections, views, and persistence.
Events is a module that can be mixed in to any object, giving the object the ability to bind and trigger custom named events. Events do not have to be declared before they are bound, and may take passed arguments. For example:
var obj = {};
_.extend(obj, Backbone.Events);
obj.bind("alert", function(msg) {
alert("Triggered " + msg);
});
obj.trigger("alert", "an event");
bindobject.bind(event, callback)
Bind a callback function to an object. The callback will be invoked
whenever the event (specified by a string identifier) is fired.
If you have many events on a page, the convention is to use colons to
namespace them: "poll:start". Callbacks bound to the special
"all" event will be triggered when any event occurs, and are passed
the name of the event as the first argument.
unbindobject.unbind([event], [callback])
Remove a previously-bound callback function from an object. If no
callback is specified, all callbacks for the event will be
removed. If no event is specified, all bound callbacks on the object
will be removed.
triggerobject.trigger(event, [*args])
Trigger all callbacks for the given event. All subsequent arguments to
trigger will be passed along.
Models are the heart of any JavaScript application, containing the interactive data as well as a large part of the logic surrounding it: conversions, validations, computed properties, and access control. You extend Backbone.Model with your domain-specific methods, and Model provides a basic set of functionality for managing changes.
The following is a contrived example, but it demonstrates defining a model with a custom method, setting an attribute, and firing an event when the model changes. After running this code once, sidebar will be available in your browser's console, so you can play around with it.
var Sidebar = Backbone.Model.extend({
promptColor: function() {
var cssColor = prompt("Please enter a CSS color:");
this.set({color: cssColor});
}
});
window.sidebar = new Sidebar;
sidebar.bind('change:color', function(model, color) {
$('#sidebar').css({background: color});
});
sidebar.set({color: 'white'});
sidebar.promptColor();
extendBackbone.Model.extend(properties, [staticProperties])
To create a Model class of your own, you extend Backbone.Model
and provide instance properties, as well as optional properties to be attatched
directly to the constructor function.
getmodel.get(attribute)
Get the current value of an attribute from the model. For example:
note.get("title")
setmodel.set(attributes, [options])
Set a hash of attributes (one or many) on the model. If any of the attributes
change the models state, a "change" event will be fired, unless
silent is passed as an option.
If the model has a validate method, it will be validated before the attributes are set, and no changes will occur if the validation fails.
note.set({title: "October 12", content: "Lorem Ipsum Dolor Sit Amet..."});
note.set({title: "October 31"}, {silent: true});
unsetmodel.unset(attribute, [options])
Remove an attribute by deleting it from the internal attributes hash.
Fires a "change" event unless silent is passed as an option.
attributesmodel.attributes()
Return a copy of the model's attributes. This can be used for persistence,
serialization, or for augmentation before being handed off to a view.
var artist = new Backbone.Model({
firstName: "Wassily",
lastName: "Kandinsky"
});
artist.set({birthday: "December 16, 1866"});
alert(JSON.stringify(artist.attributes()));
savemodel.save(attributes, [options])
Save a model to your database (or alternative persistence layer),
by delegating to Backbone.sync. If the model has a validate
method, and validation fails, the model will not be saved. If the model
isNew(), the save will be an HTTP POST, if the model already
exists on the server, the save will be a PUT. Accepts
success and error callbacks in the options hash.
Backbone.sync = function(type, model) {
alert(type + " " + JSON.stringify(model));
};
var book = new Backbone.Model({
title: "The Rough Riders",
author: "Theodore Roosevelt"
});
book.save();
destroymodel.destroy([options])
Destroys the model on the server by delegating an HTTP DELETE
request to Backbone.sync. Accepts
success and error callbacks in the options hash.
book.destroy({
success: function(model, response) {
...
}
});
validatemodel.validate(attributes)
This method is left undefined, and you're encouraged to override it with
your custom validation logic, if you have any that can be performed
in JavaScript. validate is called before set and
save, and is passed the attributes that are about to be updated.
If the model and attributes are valid, don't return anything from validate;
if the attributes are invalid, return an error of your choosing. It
can be as simple as a string error message to be displayed, or a complete
error object that describes the error programmatically. set and
save will not continue if validate returns an error.
Failed validations trigger an "error" event.
var Chapter = Backbone.Model.extend({
validate: function(attrs) {
if (attrs.end < attrs.start) {
return "can't end before it starts";
}
}
});
var one = new Chapter({
title : "Chapter One: The Beginning"
});
one.bind("error", function(model, error) {
alert(model.get("title") + " " + error);
});
one.set({
start: 15,
end: 10
});
urlmodel.url()
Returns the relative URL where the model's resource would be located on
the server. If your models are located somewhere else, override this method
with the correct logic. Generates URLs of the form: "/[collection]/[id]".
A model with an id of 101, stored in a Bindable.Collection with a url of "/notes", would have this URL: "/notes/101"
clonemodel.clone()
Create a new instance of a model with identical attributes.
isNewmodel.isNew()
Has this model been saved to the server yet? If the model does not yet have
an id, it is considered to be new.
changemodel.change()
If you've been passing {silent: true} to set in order to
aggregate rapid changes to a model, you'll want to fire the "change"
event when you're finished. Call model.change() to trigger it.
hasChangedmodel.hasChanged([attribute])
Has the model changed since the last "change" event? If an attribute
is passed, returns true if that specific attribute has changed.
book.bind("change", function() {
if (book.hasChanged("title")) {
...
}
});
changedAttributesmodel.changedAttributes([attributes])
Retrieve a hash of only the model's attributes that have changed. Optionally,
an external attributes hash can be passed in, returning
the attributes in that hash which differ from the model. This can be used
to figure out which portions of a view should be updated, or what calls
need to be made to sync the changes to the server.
previousmodel.previous(attribute)
During a "change" event, this method can be used to get the
previous value of a changed attribute.
var bill = new Backbone.Model({
name: "Bill Smith"
});
bill.bind("change:name", function(model, name) {
alert("Changed name from " + bill.previous("name") + " to " + name);
});
bill.set({name : "Bill Jones"});
previousAttributesmodel.previousAttributes()
Return a copy of the model's previous attributes. Useful for getting a
diff between versions of a model, or getting back to a valid state after
an error occurs.
Collections are ordered sets of models. You can bind callbacks to be notified when any model in the collection is changed, listen for "add" and "remove" events, fetch the collection from the server, and use a full suite of Underscore.js functions.
Underscore Methods (24)
Backbone proxies to Underscore.js to provide 24 iteration functions
on Backbone.Collection. They aren't all documented here, but
see the Underscore documentation for the full details…
Books.each(function(book) {
book.publish();
});
var titles = Books.map(function(book) {
return book.get("title");
});
var publishedBooks = Books.filter(function(book) {
return book.get("published") === true;
});
var alphabetical = Books.sortBy(function(book) {
return book.author.get("name").toLowerCase();
});
0.1.0
Initial Backbone release.