PageRenderTime 120ms CodeModel.GetById 3ms app.highlight 101ms RepoModel.GetById 1ms app.codeStats 0ms

/chapters/03-internals.md

https://gitlab.com/OpenBookPlatform/backbone-fundamentals
Markdown | 2069 lines | 1503 code | 566 blank | 0 comment | 0 complexity | fb7c9d0a954a8d2e3aa2bb060493675d MD5 | raw file
   1# Backbone Basics
   2
   3In this section, you'll learn the essentials of Backbone's models, views, collections, events, and routers. This isn't by any means a replacement for the official documentation, but it will help you understand many of the core concepts behind Backbone before you start building applications using it.
   4
   5### Getting set up
   6
   7Before we dive into more code examples, let's define some boilerplate markup you can use to specify the dependencies Backbone requires. This boilerplate can be reused in many ways with little to no alteration and will allow you to run code from examples with ease.
   8
   9You can paste the following into your text editor of choice, replacing the commented line between the script tags with the JavaScript from any given example:
  10
  11```html
  12<!DOCTYPE HTML>
  13<html>
  14<head>
  15    <meta charset="UTF-8">
  16    <title>Title</title>
  17</head>
  18<body>
  19
  20<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  21<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
  22<script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>
  23<script>
  24  // Your code goes here
  25</script>
  26</body>
  27</html>
  28```
  29
  30You can then save and run the file in your browser of choice, such as Chrome or Firefox. Alternatively, if you prefer working with an online code editor, [jsFiddle](http://jsfiddle.net/jnf8B/) and [jsBin](http://jsbin.com/iwiwox/1/edit) versions of this boilerplate are also available.
  31
  32Most examples can also be run directly from within the console in your browser's developer tools, assuming you've loaded the boilerplate HTML page so that Backbone and its dependencies are available for use.
  33
  34For Chrome, you can open up the DevTools via the Chrome menu in the top right hand corner: select "Tools > Developer Tools" or alternatively use the Control + Shift + I shortcut on Windows/Linux or Command + Option + I on Mac. 
  35
  36![](img/devtools.png)
  37
  38Next, switch to the Console tab, from where you can enter in and run any piece of JavaScript code by hitting the return key. You can also use the Console as a multi-line editor using the Shift + Enter shortcut on Windows, or Ctrl + Enter shortcut on Mac to move from the end of one line to the start of another.
  39 
  40
  41## Models
  42
  43Backbone models contain data for an application as well as the logic around this data. For example, we can use a model to represent the concept of a todo item including its attributes like title (todo content) and completed (current state of the todo).
  44
  45Models can be created by extending `Backbone.Model` as follows:
  46
  47```javascript
  48var Todo = Backbone.Model.extend({});
  49
  50// We can then create our own concrete instance of a (Todo) model
  51// with no values at all:
  52var todo1 = new Todo();
  53// Following logs: {}
  54console.log(JSON.stringify(todo1));
  55
  56// or with some arbitrary data:
  57var todo2 = new Todo({
  58  title: 'Check the attributes of both model instances in the console.',
  59  completed: true
  60});
  61
  62// Following logs: {"title":"Check the attributes of both model instances in the console.","completed":true}
  63console.log(JSON.stringify(todo2));
  64```
  65
  66#### Initialization
  67
  68The `initialize()` method is called when a new instance of a model is created. Its use is optional; however you'll see why it's good practice to use it below.
  69
  70```javascript
  71var Todo = Backbone.Model.extend({
  72  initialize: function(){
  73      console.log('This model has been initialized.');
  74  }
  75});
  76
  77var myTodo = new Todo();
  78// Logs: This model has been initialized.
  79```
  80
  81**Default values**
  82
  83There are times when you want your model to have a set of default values (e.g., in a scenario where a complete set of data isn't provided by the user). This can be set using a property called `defaults` in your model.
  84
  85```javascript
  86var Todo = Backbone.Model.extend({
  87  // Default todo attribute values
  88  defaults: {
  89    title: '',
  90    completed: false
  91  }
  92});
  93
  94// Now we can create our concrete instance of the model
  95// with default values as follows:
  96var todo1 = new Todo();
  97
  98// Following logs: {"title":"","completed":false}
  99console.log(JSON.stringify(todo1));
 100
 101// Or we could instantiate it with some of the attributes (e.g., with custom title):
 102var todo2 = new Todo({
 103  title: 'Check attributes of the logged models in the console.'
 104});
 105
 106// Following logs: {"title":"Check attributes of the logged models in the console.","completed":false}
 107console.log(JSON.stringify(todo2));
 108
 109// Or override all of the default attributes:
 110var todo3 = new Todo({
 111  title: 'This todo is done, so take no action on this one.',
 112  completed: true
 113});
 114
 115// Following logs: {"title":"This todo is done, so take no action on this one.","completed":true} 
 116console.log(JSON.stringify(todo3));
 117```
 118
 119#### Getters & Setters
 120
 121**Model.get()**
 122
 123`Model.get()` provides easy access to a model's attributes.
 124
 125```javascript
 126var Todo = Backbone.Model.extend({
 127  // Default todo attribute values
 128  defaults: {
 129    title: '',
 130    completed: false
 131  }
 132});
 133
 134var todo1 = new Todo();
 135console.log(todo1.get('title')); // empty string
 136console.log(todo1.get('completed')); // false
 137
 138var todo2 = new Todo({
 139  title: "Retrieved with model's get() method.",
 140  completed: true
 141});
 142console.log(todo2.get('title')); // Retrieved with model's get() method.
 143console.log(todo2.get('completed')); // true
 144```
 145
 146If you need to read or clone all of a model's data attributes, use its `toJSON()` method. This method returns a copy of the attributes as an object (not a JSON string despite its name). (When `JSON.stringify()` is passed an object with a `toJSON()` method, it stringifies the return value of `toJSON()` instead of the original object. The examples in the previous section took advantage of this feature when they called `JSON.stringify()` to log model instances.)
 147
 148```javascript
 149var Todo = Backbone.Model.extend({
 150  // Default todo attribute values
 151  defaults: {
 152    title: '',
 153    completed: false
 154  }
 155});
 156
 157var todo1 = new Todo();
 158var todo1Attributes = todo1.toJSON();
 159// Following logs: {"title":"","completed":false} 
 160console.log(todo1Attributes);
 161
 162var todo2 = new Todo({
 163  title: "Try these examples and check results in console.",
 164  completed: true
 165});
 166
 167// logs: {"title":"Try these examples and check results in console.","completed":true}
 168console.log(todo2.toJSON());
 169```
 170
 171**Model.set()**
 172
 173`Model.set()` sets a hash containing one or more attributes on the model. When any of these attributes alter the state of the model, a "change" event is triggered on it. Change events for each attribute are also triggered and can be bound to (e.g. `change:name`, `change:age`).
 174
 175```javascript
 176var Todo = Backbone.Model.extend({
 177  // Default todo attribute values
 178  defaults: {
 179    title: '',
 180    completed: false
 181  }
 182});
 183
 184// Setting the value of attributes via instantiation
 185var myTodo = new Todo({
 186  title: "Set through instantiation."
 187});
 188console.log('Todo title: ' + myTodo.get('title')); // Todo title: Set through instantiation.
 189console.log('Completed: ' + myTodo.get('completed')); // Completed: false
 190
 191// Set single attribute value at a time through Model.set():
 192myTodo.set("title", "Title attribute set through Model.set().");
 193console.log('Todo title: ' + myTodo.get('title')); // Todo title: Title attribute set through Model.set().
 194console.log('Completed: ' + myTodo.get('completed')); // Completed: false
 195
 196// Set map of attributes through Model.set():
 197myTodo.set({
 198  title: "Both attributes set through Model.set().",
 199  completed: true
 200});
 201console.log('Todo title: ' + myTodo.get('title')); // Todo title: Both attributes set through Model.set().
 202console.log('Completed: ' + myTodo.get('completed')); // Completed: true
 203```
 204
 205**Direct access**
 206
 207Models expose an `.attributes` attribute which represents an internal hash containing the state of that model. This is generally in the form of a JSON object similar to the model data you might find on the server but can take other forms.
 208
 209Setting values through the `.attributes` attribute on a model bypasses triggers bound to the model.
 210
 211Passing `{silent:true}` on change doesn't delay individual `"change:attr"` events. Instead they are silenced entirely:
 212
 213```javascript
 214var Person = new Backbone.Model();
 215Person.on("change:name", function() { console.log('Name changed'); });
 216Person.set({name: 'Andrew'});
 217// log entry: Name changed
 218
 219Person.set({name: 'Jeremy'}, {silent: true});
 220// no log entry
 221
 222console.log(Person.hasChanged("name"));
 223// true: change was recorded
 224console.log(Person.hasChanged(null));
 225// true: something (anything) has changed
 226```
 227
 228Remember where possible it is best practice to use `Model.set()`, or direct instantiation as explained earlier.
 229
 230#### Listening for changes to your model
 231
 232If you want to receive a notification when a Backbone model changes you can bind a listener to the model for its change event. A convenient place to add listeners is in the `initialize()` function as shown below:
 233
 234```javascript
 235var Todo = Backbone.Model.extend({
 236  // Default todo attribute values
 237  defaults: {
 238    title: '',
 239    completed: false
 240  },
 241  initialize: function(){
 242    console.log('This model has been initialized.');
 243    this.on('change', function(){
 244        console.log('- Values for this model have changed.');
 245    });
 246  }
 247});
 248
 249var myTodo = new Todo();
 250
 251myTodo.set('title', 'The listener is triggered whenever an attribute value changes.');
 252console.log('Title has changed: ' + myTodo.get('title'));
 253
 254
 255myTodo.set('completed', true);
 256console.log('Completed has changed: ' + myTodo.get('completed'));
 257
 258myTodo.set({
 259  title: 'Changing more than one attribute at the same time only triggers the listener once.',
 260  completed: true
 261});
 262
 263// Above logs:
 264// This model has been initialized.
 265// - Values for this model have changed.
 266// Title has changed: The listener is triggered whenever an attribute value changes.
 267// - Values for this model have changed.
 268// Completed has changed: true
 269// - Values for this model have changed.
 270```
 271
 272You can also listen for changes to individual attributes in a Backbone model. In the following example, we log a message whenever a specific attribute (the title of our Todo model) is altered.
 273
 274```javascript
 275var Todo = Backbone.Model.extend({
 276  // Default todo attribute values
 277  defaults: {
 278    title: '',
 279    completed: false
 280  },
 281
 282  initialize: function(){
 283    console.log('This model has been initialized.');
 284    this.on('change:title', function(){
 285        console.log('Title value for this model has changed.');
 286    });
 287  },
 288
 289  setTitle: function(newTitle){
 290    this.set({ title: newTitle });
 291  }
 292});
 293
 294var myTodo = new Todo();
 295
 296// Both of the following changes trigger the listener:
 297myTodo.set('title', 'Check what\'s logged.');
 298myTodo.setTitle('Go fishing on Sunday.');
 299
 300// But, this change type is not observed, so no listener is triggered:
 301myTodo.set('completed', true);
 302console.log('Todo set as completed: ' + myTodo.get('completed'));
 303
 304// Above logs:
 305// This model has been initialized.
 306// Title value for this model has changed.
 307// Title value for this model has changed.
 308// Todo set as completed: true
 309```
 310
 311
 312#### Validation
 313
 314Backbone supports model validation through `model.validate()`, which allows checking the attribute values for a model prior to setting them. By default, validation occurs when the model is persisted using the `save()` method or when `set()` is called if `{validate:true}` is passed as an argument.
 315
 316```javascript
 317var Person = new Backbone.Model({name: 'Jeremy'});
 318
 319// Validate the model name
 320Person.validate = function(attrs) {
 321  if (!attrs.name) {
 322    return 'I need your name';
 323  }
 324};
 325
 326// Change the name
 327Person.set({name: 'Samuel'});
 328console.log(Person.get('name'));
 329// 'Samuel'
 330
 331// Remove the name attribute, force validation
 332Person.unset('name', {validate: true});
 333// false
 334```
 335
 336Above, we also use the `unset()` method, which removes an attribute by deleting it from the internal model attributes hash.
 337
 338Validation functions can be as simple or complex as necessary. If the attributes provided are valid, nothing should be returned from `.validate()`. If they are invalid, an error value should be returned instead. 
 339
 340Should an error be returned:
 341
 342* An `invalid` event will be triggered, setting the `validationError` property on the model with the value which is returned by this method. 
 343* `.save()` will not continue and the attributes of the model will not be modified on the server.
 344
 345A more complete validation example can be seen below:
 346
 347```javascript
 348var Todo = Backbone.Model.extend({
 349  defaults: {
 350    completed: false
 351  },
 352
 353  validate: function(attributes){
 354    if(attributes.title === undefined){
 355        return "Remember to set a title for your todo.";
 356    }
 357  },
 358
 359  initialize: function(){
 360    console.log('This model has been initialized.');
 361    this.on("invalid", function(model, error){
 362        console.log(error);
 363    });
 364  }
 365});
 366
 367var myTodo = new Todo();
 368myTodo.set('completed', true, {validate: true}); // logs: Remember to set a title for your todo.
 369console.log('completed: ' + myTodo.get('completed')); // completed: false
 370```
 371
 372**Note**: the `attributes` object passed to the `validate` function represents what the attributes would be after completing the current `set()` or `save()`. This object is distinct from the current attributes of the model and from the parameters passed to the operation. Since it is created by shallow copy, it is not possible to change any Number, String, or Boolean attribute of the input within the function, but it *is* possible to change attributes in nested objects.
 373
 374An example of this (by @fivetanley) is available [here](http://jsfiddle.net/2NdDY/270/).
 375
 376Note also, that validation on initialization is possible but of limited use, as the object being constructed is internally marked invalid but nevertheless passed back to the caller (continuing the above example):
 377
 378```javascript
 379var emptyTodo = new Todo(null, {validate: true});
 380console.log(emptyTodo.validationError);
 381```
 382
 383## Views
 384
 385Views in Backbone don't contain the HTML markup for your application; they contain the logic behind the presentation of the model's data to the user. This is usually achieved using JavaScript templating (e.g., Underscore Microtemplates, Mustache, jQuery-tmpl, etc.). A view's `render()` method can be bound to a model's `change()` event, enabling the view to instantly reflect model changes without requiring a full page refresh.
 386
 387
 388#### Creating new views
 389
 390Creating a new view is relatively straightforward and similar to creating new models. To create a new View, simply extend `Backbone.View`. We introduced the sample TodoView below in the previous chapter; now let's take a closer look at how it works:
 391
 392```javascript
 393var TodoView = Backbone.View.extend({
 394
 395  tagName:  'li',
 396
 397  // Cache the template function for a single item.
 398  todoTpl: _.template( "An example template" ),
 399
 400  events: {
 401    'dblclick label': 'edit',
 402    'keypress .edit': 'updateOnEnter',
 403    'blur .edit':   'close'
 404  },
 405
 406  initialize: function (options) {
 407    // In Backbone 1.1.0, if you want to access passed options in
 408    // your view, you will need to save them as follows:
 409    this.options = options || {};
 410  },
 411
 412  // Re-render the title of the todo item.
 413  render: function() {
 414    this.$el.html( this.todoTpl( this.model.attributes ) );
 415    this.input = this.$('.edit');
 416    return this;
 417  },
 418
 419  edit: function() {
 420    // executed when todo label is double clicked
 421  },
 422
 423  close: function() {
 424    // executed when todo loses focus
 425  },
 426
 427  updateOnEnter: function( e ) {
 428    // executed on each keypress when in todo edit mode,
 429    // but we'll wait for enter to get in action
 430  }
 431});
 432
 433var todoView = new TodoView();
 434
 435// log reference to a DOM element that corresponds to the view instance
 436console.log(todoView.el); // logs <li></li>
 437```
 438
 439#### What is `el`?
 440
 441The central property of a view is `el` (the value logged in the last statement of the example). What is `el` and how is it defined? 
 442
 443`el` is basically a reference to a DOM element and all views must have one. Views can use `el` to compose their element's content and then insert it into the DOM all at once, which makes for faster rendering because the browser performs the minimum required number of reflows and repaints.
 444
 445There are two ways to associate a DOM element with a view: a new element can be created for the view and subsequently added to the DOM or a reference can be made to an element which already exists in the page.
 446
 447If you want to create a new element for your view, set any combination of the following properties on the view: `tagName`, `id`, and `className`. A new element will be created for you by the framework and a reference to it will be available at the `el` property. If nothing is specified `tagName` defaults to `div`.
 448
 449In the example above, `tagName` is set to 'li', resulting in creation of an li element. The following example creates a ul element with id and class attributes:
 450
 451```javascript
 452var TodosView = Backbone.View.extend({
 453  tagName: 'ul', // required, but defaults to 'div' if not set
 454  className: 'container', // optional, you can assign multiple classes to 
 455                          // this property like so: 'container homepage'
 456  id: 'todos' // optional
 457});
 458
 459var todosView = new TodosView();
 460console.log(todosView.el); // logs <ul id="todos" class="container"></ul>
 461```
 462
 463The above code creates the DOM element below but doesn't append it to the DOM.
 464
 465```html
 466<ul id="todos" class="container"></ul>
 467```
 468
 469If the element already exists in the page, you can set `el` as a CSS selector that matches the element.
 470
 471```javascript
 472el: '#footer'
 473```
 474
 475Alternatively, you can set `el` to an existing element when creating the view:
 476
 477```javascript
 478var todosView = new TodosView({el: $('#footer')});
 479```
 480
 481Note: When declaring a View, `options`, `el`, `tagName`, `id` and `className` may be defined as functions, if you want their values to be determined at runtime.
 482
 483**$el and $()**
 484
 485View logic often needs to invoke jQuery or Zepto functions on the `el` element and elements nested within it. Backbone makes it easy to do so by defining the `$el` property and `$()` function. The `view.$el` property is equivalent to `$(view.el)` and `view.$(selector)` is equivalent to `$(view.el).find(selector)`. In our TodoView example's render method, we see `this.$el` used to set the HTML of the element and `this.$()` used to find subelements of class 'edit'.
 486
 487**setElement**
 488
 489If you need to apply an existing Backbone view to a different DOM element `setElement` can be used for this purpose. Overriding this.el needs to both change the DOM reference and re-bind events to the new element (and unbind from the old). 
 490
 491`setElement` will create a cached `$el` reference for you, moving the delegated events for a view from the old element to the new one.
 492
 493```javascript
 494
 495// We create two DOM elements representing buttons
 496// which could easily be containers or something else
 497var button1 = $('<button></button>');
 498var button2 = $('<button></button>');
 499
 500// Define a new view
 501var View = Backbone.View.extend({
 502      events: {
 503        click: function(e) {
 504          console.log(view.el === e.target);
 505        }
 506      }
 507    });
 508
 509// Create a new instance of the view, applying it
 510// to button1
 511var view = new View({el: button1});
 512
 513// Apply the view to button2 using setElement
 514view.setElement(button2);
 515
 516button1.trigger('click'); 
 517button2.trigger('click'); // returns true
 518```
 519
 520The "el" property represents the markup portion of the view that will be rendered; to get the view to actually render to the page, you need to add it as a new element or append it to an existing element.
 521
 522```javascript
 523
 524// We can also provide raw markup to setElement
 525// as follows (just to demonstrate it can be done):
 526var view = new Backbone.View;
 527view.setElement('<p><a><b>test</b></a></p>');
 528console.log(view.$('a b').html()); // outputs "test"
 529```
 530
 531**Understanding `render()`**
 532
 533`render()` is an optional function that defines the logic for rendering a template. We'll use Underscore's micro-templating in these examples, but remember you can use other templating frameworks if you prefer. Our example will reference the following HTML markup:
 534
 535```html
 536<!doctype html>
 537<html lang="en">
 538<head>
 539  <meta charset="utf-8">
 540  <title></title>
 541  <meta name="description" content="">
 542</head>
 543<body>
 544  <div id="todo">
 545  </div>
 546  <script type="text/template" id="item-template">
 547    <div>
 548      <input id="todo_complete" type="checkbox" <%= completed ? 'checked="checked"' : '' %>>
 549      <%= title %>
 550    </div>
 551  </script>
 552  <script src="underscore-min.js"></script>
 553  <script src="backbone-min.js"></script>
 554  <script src="jquery-min.js"></script>
 555  <script src="example.js"></script>
 556</body>
 557</html>
 558```
 559
 560The `_.template` method in Underscore compiles JavaScript templates into functions which can be evaluated for rendering. In the TodoView, I'm passing the markup from the template with id `item-template` to `_.template()` to be compiled and stored in the todoTpl property when the view is created.
 561
 562The `render()` method uses this template by passing it the `toJSON()` encoding of the attributes of the model associated with the view. The template returns its markup after using the model's title and completed flag to evaluate the expressions containing them. I then set this markup as the HTML content of the `el` DOM element using the `$el` property.
 563
 564Presto! This populates the template, giving you a data-complete set of markup in just a few short lines of code.
 565
 566
 567
 568A common Backbone convention is to return `this` at the end of `render()`. This is useful for a number of reasons, including:
 569
 570* Making views easily reusable in other parent views.
 571* Creating a list of elements without rendering and painting each of them individually, only to be drawn once the entire list is populated.
 572
 573Let's try to implement the latter of these. The `render` method of a simple ListView which doesn't use an ItemView for each item could be written:
 574
 575```javascript
 576
 577var ListView = Backbone.View.extend({
 578
 579  // Compile a template for this view. In this case '...'
 580  // is a placeholder for a template such as 
 581  // $("#list_template").html() 
 582  template: _.template(),
 583  
 584  render: function() {
 585    this.$el.html(this.template(this.model.attributes));
 586    return this;
 587  }
 588});
 589```
 590
 591Simple enough. Let's now assume a decision is made to construct the items using an ItemView to provide enhanced behaviour to our list. The ItemView could be written:
 592
 593```javascript
 594
 595var ItemView = Backbone.View.extend({
 596  events: {},
 597  render: function(){
 598    this.$el.html(this.template(this.model.attributes));
 599    return this;
 600  }
 601});
 602
 603```
 604
 605Note the usage of `return this;` at the end of `render`. This common pattern enables us to reuse the view as a sub-view. We can also use it to pre-render the view prior to rendering. Using this requires that we make a change to our ListView's `render` method as follows:
 606
 607```javascript
 608
 609var ListView = Backbone.View.extend({
 610  render: function(){
 611
 612    // Assume our model exposes the items we will
 613    // display in our list
 614    var items = this.model.get('items');
 615
 616    // Loop through each of our items using the Underscore
 617    // _.each iterator
 618    _.each(items, function(item){
 619
 620      // Create a new instance of the ItemView, passing 
 621      // it a specific model item
 622      var itemView = new ItemView({ model: item });
 623      // The itemView's DOM element is appended after it
 624      // has been rendered. Here, the 'return this' is helpful
 625      // as the itemView renders its model. Later, we ask for 
 626      // its output ("el")
 627      this.$el.append( itemView.render().el );
 628    }, this);
 629  }
 630});
 631```
 632
 633**The `events` hash**
 634
 635
 636The Backbone `events` hash allows us to attach event listeners to either `el`-relative custom selectors, or directly to `el` if no selector is provided. An event takes the form of a key-value pair `'eventName selector': 'callbackFunction'` and a number of DOM event-types are supported, including `click`, `submit`, `mouseover`, `dblclick` and more.
 637
 638```javascript
 639
 640// A sample view
 641var TodoView = Backbone.View.extend({
 642  tagName:  'li',
 643
 644  // with an events hash containing DOM events
 645  // specific to an item:
 646  events: {
 647    'click .toggle': 'toggleCompleted',
 648    'dblclick label': 'edit',
 649    'keypress .edit': 'updateOnEnter',
 650    'click .destroy': 'clear',
 651    'blur .edit': 'close'
 652  },
 653```
 654
 655What isn't instantly obvious is that while Backbone uses jQuery's `.delegate()` underneath, it goes further by extending it so that `this` always refers to the current view object within callback functions. The only thing to really keep in mind is that any string callback supplied to the events attribute must have a corresponding function with the same name within the scope of your view. 
 656
 657The declarative, delegated jQuery events means that you don't have to worry about whether a particular element has been rendered to the DOM yet or not. Usually with jQuery you have to worry about "presence or absence in the DOM" all the time when binding events.
 658
 659In our TodoView example, the edit callback is invoked when the user double-clicks a label element within the `el` element, updateOnEnter is called for each keypress in an element with class 'edit', and close executes when an element with class 'edit' loses focus. Each of these callback functions can use `this` to refer to the TodoView object.
 660
 661Note that you can also bind methods yourself using `_.bind(this.viewEvent, this)`, which is effectively what the value in each event's key-value pair is doing. Below we use `_.bind` to re-render our view when a model changes.
 662
 663```javascript
 664
 665var TodoView = Backbone.View.extend({
 666  initialize: function() {
 667    this.model.bind('change', _.bind(this.render, this));
 668  }
 669});
 670```
 671
 672`_.bind` only works on one method at a time, but effectively binds a function to an object so that anytime the function is called the value of `this` will be the object. `_.bind` also supports passing in arguments to the function in order to fill them in advance - a technique known as [partial application](http://benalman.com/news/2012/09/partial-application-in-javascript/).
 673
 674
 675## Collections
 676
 677Collections are sets of Models and are created by extending `Backbone.Collection`.
 678
 679Normally, when creating a collection you'll also want to define a property specifying the type of model that your collection will contain, along with any instance properties required.
 680
 681In the following example, we create a TodoCollection that will contain our Todo models:
 682
 683```javascript
 684var Todo = Backbone.Model.extend({
 685  defaults: {
 686    title: '',
 687    completed: false
 688  }
 689});
 690
 691var TodosCollection = Backbone.Collection.extend({
 692  model: Todo
 693});
 694
 695var myTodo = new Todo({title:'Read the whole book', id: 2});
 696
 697// pass array of models on collection instantiation
 698var todos = new TodosCollection([myTodo]);
 699console.log("Collection size: " + todos.length); // Collection size: 1
 700```
 701
 702#### Adding and Removing Models
 703
 704The preceding example populated the collection using an array of models when it was instantiated. After a collection has been created, models can be added and removed using the `add()` and `remove()` methods:
 705
 706```javascript
 707var Todo = Backbone.Model.extend({
 708  defaults: {
 709    title: '',
 710    completed: false
 711  }
 712});
 713
 714var TodosCollection = Backbone.Collection.extend({
 715  model: Todo
 716});
 717
 718var a = new Todo({ title: 'Go to Jamaica.'}),
 719    b = new Todo({ title: 'Go to China.'}),
 720    c = new Todo({ title: 'Go to Disneyland.'});
 721
 722var todos = new TodosCollection([a,b]);
 723console.log("Collection size: " + todos.length);
 724// Logs: Collection size: 2
 725
 726todos.add(c);
 727console.log("Collection size: " + todos.length);
 728// Logs: Collection size: 3
 729
 730todos.remove([a,b]);
 731console.log("Collection size: " + todos.length);
 732// Logs: Collection size: 1
 733
 734todos.remove(c);
 735console.log("Collection size: " + todos.length);
 736// Logs: Collection size: 0
 737```
 738
 739Note that `add()` and `remove()` accept both individual models and lists of models.
 740
 741Also note that when using `add()` on a collection, passing `{merge: true}` causes duplicate models to have their attributes merged in to the existing models, instead of being ignored.
 742
 743```javascript
 744var items = new Backbone.Collection;
 745items.add([{ id : 1, name: "Dog" , age: 3}, { id : 2, name: "cat" , age: 2}]);
 746items.add([{ id : 1, name: "Bear" }], {merge: true });
 747items.add([{ id : 2, name: "lion" }]); // merge: false
 748 
 749console.log(JSON.stringify(items.toJSON()));
 750// [{"id":1,"name":"Bear","age":3},{"id":2,"name":"cat","age":2}]
 751```
 752
 753#### Retrieving Models
 754
 755There are a few different ways to retrieve a model from a collection. The most straight-forward is to use `Collection.get()` which accepts a single id as follows:
 756
 757```javascript
 758var myTodo = new Todo({title:'Read the whole book', id: 2});
 759
 760// pass array of models on collection instantiation
 761var todos = new TodosCollection([myTodo]);
 762
 763var todo2 = todos.get(2);
 764
 765// Models, as objects, are passed by reference
 766console.log(todo2 === myTodo); // true
 767```
 768
 769In client-server applications, collections contain models obtained from the server. Anytime you're exchanging data between the client and a server, you will need a way to uniquely identify models. In Backbone, this is done using the `id`, `cid`, and `idAttribute` properties.
 770
 771Each model in Backbone has an `id`, which is a unique identifier that is either an integer or string (e.g., a UUID). Models also have a `cid` (client id) which is automatically generated by Backbone when the model is created. Either identifier can be used to retrieve a model from a collection. 
 772
 773The main difference between them is that the `cid` is generated by Backbone; it is helpful when you don't have a true id - this may be the case if your model has yet to be saved to the server or you aren't saving it to a database.
 774
 775The `idAttribute` is the identifying attribute name of the model returned from the server (i.e., the `id` in your database). This tells Backbone which data field from the server should be used to populate the `id` property (think of it as a mapper). By default, it assumes `id`, but this can be customized as needed. For instance, if your server sets a unique attribute on your model named "userId" then you would set `idAttribute` to "userId" in your model definition.
 776
 777The value of a model's idAttribute should be set by the server when the model is saved. After this point you shouldn't need to set it manually, unless further control is required. 
 778
 779Internally, `Backbone.Collection` contains an array of models enumerated by their `id` property, if the model instances happen to have one. When `collection.get(id)` is called, this array is checked for existence of the model instance with the corresponding `id`.
 780
 781```javascript
 782// extends the previous example
 783
 784var todoCid = todos.get(todo2.cid);
 785
 786// As mentioned in previous example, 
 787// models are passed by reference
 788console.log(todoCid === myTodo); // true
 789```
 790
 791#### Listening for events
 792
 793As collections represent a group of items, we can listen for `add` and `remove` events which occur when models are added to or removed from a collection. Here's an example:
 794
 795```javascript
 796var TodosCollection = new Backbone.Collection();
 797
 798TodosCollection.on("add", function(todo) {
 799  console.log("I should " + todo.get("title") + ". Have I done it before? "  + (todo.get("completed") ? 'Yeah!': 'No.' ));
 800});
 801
 802TodosCollection.add([
 803  { title: 'go to Jamaica', completed: false },
 804  { title: 'go to China', completed: false },
 805  { title: 'go to Disneyland', completed: true }
 806]);
 807
 808// The above logs:
 809// I should go to Jamaica. Have I done it before? No.
 810// I should go to China. Have I done it before? No.
 811// I should go to Disneyland. Have I done it before? Yeah!
 812```
 813
 814In addition, we're also able to bind to a `change` event to listen for changes to any of the models in the collection.
 815
 816```javascript
 817var TodosCollection = new Backbone.Collection();
 818
 819// log a message if a model in the collection changes
 820TodosCollection.on("change:title", function(model) {
 821    console.log("Changed my mind! I should " + model.get('title'));
 822});
 823
 824TodosCollection.add([
 825  { title: 'go to Jamaica.', completed: false, id: 3 },
 826]);
 827
 828var myTodo = TodosCollection.get(3);
 829
 830myTodo.set('title', 'go fishing');
 831// Logs: Changed my mind! I should go fishing
 832```
 833
 834jQuery-style event maps of the form `obj.on({click: action})` can also be used. These can be clearer than needing three separate calls to `.on` and should align better with the events hash used in Views:
 835
 836```javascript
 837
 838var Todo = Backbone.Model.extend({
 839  defaults: {
 840    title: '',
 841    completed: false
 842  }
 843});
 844
 845var myTodo = new Todo();
 846myTodo.set({title: 'Buy some cookies', completed: true});
 847
 848myTodo.on({
 849   'change:title' : titleChanged,
 850   'change:completed' : stateChanged
 851});
 852
 853function titleChanged(){
 854  console.log('The title was changed!');
 855}
 856
 857function stateChanged(){
 858  console.log('The state was changed!');
 859}
 860
 861myTodo.set({title: 'Get the groceries'});
 862// The title was changed! 
 863```
 864
 865Backbone events also support a [once()](http://backbonejs.org/#Events-once) method, which ensures that a callback only fires one time when a notification arrives. It is similar to Node's [once](http://nodejs.org/api/events.html#events_emitter_once_event_listener), or jQuery's [one](http://api.jquery.com/one/). This is particularly useful for when you want to say "the next time something happens, do this".
 866
 867```javascript
 868// Define an object with two counters
 869var TodoCounter = { counterA: 0, counterB: 0 };
 870// Mix in Backbone Events
 871_.extend(TodoCounter, Backbone.Events);
 872
 873// Increment counterA, triggering an event
 874var incrA = function(){ 
 875  TodoCounter.counterA += 1; 
 876  // This triggering will not 
 877  // produce any effect on the counters
 878  TodoCounter.trigger('event'); 
 879};
 880
 881// Increment counterB
 882var incrB = function(){ 
 883  TodoCounter.counterB += 1; 
 884};
 885
 886// Use once rather than having to explicitly unbind
 887// our event listener
 888TodoCounter.once('event', incrA);
 889TodoCounter.once('event', incrB);
 890
 891// Trigger the event for the first time
 892TodoCounter.trigger('event');
 893
 894// Check out output
 895console.log(TodoCounter.counterA === 1); // true
 896console.log(TodoCounter.counterB === 1); // true
 897```
 898
 899`counterA` and `counterB` should only have been incremented once.
 900
 901#### Resetting/Refreshing Collections
 902
 903Rather than adding or removing models individually, you might want to update an entire collection at once. `Collection.set()` takes an array of models and performs the necessary add, remove, and change operations required to update the collection.
 904
 905```javascript
 906var TodosCollection = new Backbone.Collection();
 907
 908TodosCollection.add([
 909    { id: 1, title: 'go to Jamaica.', completed: false },
 910    { id: 2, title: 'go to China.', completed: false },
 911    { id: 3, title: 'go to Disneyland.', completed: true }
 912]);
 913
 914// we can listen for add/change/remove events
 915TodosCollection.on("add", function(model) {
 916  console.log("Added " + model.get('title'));
 917});
 918
 919TodosCollection.on("remove", function(model) {
 920  console.log("Removed " + model.get('title'));
 921});
 922
 923TodosCollection.on("change:completed", function(model) {
 924  console.log("Completed " + model.get('title'));
 925});
 926
 927TodosCollection.set([
 928    { id: 1, title: 'go to Jamaica.', completed: true },
 929    { id: 2, title: 'go to China.', completed: false },
 930    { id: 4, title: 'go to Disney World.', completed: false }
 931]);
 932
 933// Above logs:
 934// Completed go to Jamaica.
 935// Removed go to Disneyland.
 936// Added go to Disney World.
 937```
 938
 939If you need to simply replace the entire content of the collection then `Collection.reset()` can be used:
 940
 941```javascript
 942var TodosCollection = new Backbone.Collection();
 943
 944// we can listen for reset events
 945TodosCollection.on("reset", function() {
 946  console.log("Collection reset.");
 947});
 948
 949TodosCollection.add([
 950  { title: 'go to Jamaica.', completed: false },
 951  { title: 'go to China.', completed: false },
 952  { title: 'go to Disneyland.', completed: true }
 953]);
 954
 955console.log('Collection size: ' + TodosCollection.length); // Collection size: 3
 956
 957TodosCollection.reset([
 958  { title: 'go to Cuba.', completed: false }
 959]);
 960// Above logs 'Collection reset.'
 961
 962console.log('Collection size: ' + TodosCollection.length); // Collection size: 1
 963```
 964
 965Another useful tip is to use `reset` with no arguments to clear out a collection completely. This is handy when dynamically loading a new page of results where you want to blank out the current page of results.
 966
 967```javascript
 968myCollection.reset();
 969```
 970
 971Note that using `Collection.reset()` doesn't fire any `add` or `remove` events. A `reset` event is fired instead as shown in the previous example. The reason you might want to use this is to perform super-optimized rendering in extreme cases where individual events are too expensive.
 972
 973Also note that listening to a [reset](http://backbonejs.org/#Collection-reset) event, the list of previous models is available in `options.previousModels`, for convenience.
 974
 975```javascript
 976var todo = new Backbone.Model();
 977var todos = new Backbone.Collection([todo])
 978.on('reset', function(todos, options) {
 979  console.log(options.previousModels);
 980  console.log([todo]);
 981  console.log(options.previousModels[0] === todo); // true
 982});
 983todos.reset([]);
 984```
 985
 986The `set()` method available for Collections can also be used for "smart" updating of sets of models. This method attempts to perform smart updating of a collection using a specified list of models. When a model in this list isn't present in the collection, it is added. If it's present, its attributes will be merged. Models which are present in the collection but not in the list are removed.
 987
 988```javascript
 989
 990// Define a model of type 'Beatle' with a 'job' attribute
 991var Beatle = Backbone.Model.extend({
 992  defaults: {
 993    job: 'musician'
 994  }
 995});
 996
 997// Create models for each member of the Beatles
 998var john = new Beatle({ firstName: 'John', lastName: 'Lennon'});
 999var paul = new Beatle({ firstName: 'Paul', lastName: 'McCartney'});
1000var george = new Beatle({ firstName: 'George', lastName: 'Harrison'});
1001var ringo = new Beatle({ firstName: 'Ringo', lastName: 'Starr'});
1002
1003// Create a collection using our models
1004var theBeatles = new Backbone.Collection([john, paul, george, ringo]);
1005
1006// Create a separate model for Pete Best
1007var pete = new Beatle({ firstName: 'Pete', lastName: 'Best'});
1008
1009// Update the collection
1010theBeatles.set([john, paul, george, pete]);
1011
1012// Fires a `remove` event for 'Ringo', and an `add` event for 'Pete'.
1013// Updates any of John, Paul and Georges's attributes that may have
1014// changed over the years.
1015```
1016
1017#### Underscore utility functions
1018
1019Backbone takes full advantage of its hard dependency on Underscore by making many of its utilities directly available on collections:
1020
1021**`forEach`: iterate over collections**
1022
1023```javascript
1024var todos = new Backbone.Collection();
1025
1026todos.add([
1027  { title: 'go to Belgium.', completed: false },
1028  { title: 'go to China.', completed: false },
1029  { title: 'go to Austria.', completed: true }
1030]);
1031
1032// iterate over models in the collection
1033todos.forEach(function(model){
1034  console.log(model.get('title'));
1035});
1036// Above logs:
1037// go to Belgium.
1038// go to China.
1039// go to Austria.
1040```
1041
1042**`sortBy()`: sort a collection on a specific attribute**
1043
1044```javascript
1045// sort collection
1046var sortedByAlphabet = todos.sortBy(function (todo) {
1047    return todo.get("title").toLowerCase();
1048});
1049
1050console.log("- Now sorted: ");
1051
1052sortedByAlphabet.forEach(function(model){
1053  console.log(model.get('title'));
1054});
1055// Above logs:
1056// - Now sorted:
1057// go to Austria.
1058// go to Belgium.
1059// go to China.
1060```
1061
1062**`map()`: iterate through a collection, mapping each value through a transformation function**
1063
1064```javascript
1065var count = 1;
1066console.log(todos.map(function(model){
1067  return count++ + ". " + model.get('title');
1068}));
1069// Above logs:
1070//1. go to Belgium.
1071//2. go to China.
1072//3. go to Austria.
1073```
1074
1075**`min()`/`max()`: retrieve item with the min or max value of an attribute**
1076
1077```javascript
1078todos.max(function(model){
1079  return model.id;
1080}).id;
1081
1082todos.min(function(model){
1083  return model.id;
1084}).id;
1085```
1086
1087**`pluck()`: extract a specific attribute**
1088
1089```javascript
1090var captions = todos.pluck('caption');
1091// returns list of captions
1092```
1093
1094**`filter()`: filter a collection**
1095
1096*Filter by an array of model IDs*
1097
1098```javascript
1099var Todos = Backbone.Collection.extend({
1100  model: Todo,
1101  filterById: function(ids){
1102    return this.models.filter(
1103      function(c) { 
1104        return _.contains(ids, c.id); 
1105      })
1106  }
1107});
1108```
1109
1110**`indexOf()`: return the index of a particular item within a collection**
1111
1112```javascript
1113var people = new Backbone.Collection;
1114
1115people.comparator = function(a, b) {
1116  return a.get('name') < b.get('name') ? -1 : 1;
1117};
1118
1119var tom = new Backbone.Model({name: 'Tom'});
1120var rob = new Backbone.Model({name: 'Rob'});
1121var tim = new Backbone.Model({name: 'Tim'});
1122
1123people.add(tom);
1124people.add(rob);
1125people.add(tim);
1126
1127console.log(people.indexOf(rob) === 0); // true
1128console.log(people.indexOf(tim) === 1); // true
1129console.log(people.indexOf(tom) === 2); // true
1130```
1131
1132**`any()`: confirm if any of the values in a collection pass an iterator truth test**
1133
1134```javascript
1135todos.any(function(model){
1136  return model.id === 100;
1137});
1138
1139// or
1140todos.some(function(model){
1141  return model.id === 100;
1142});
1143```
1144
1145**`size()`: return the size of a collection**
1146
1147```javascript
1148todos.size();
1149
1150// equivalent to
1151todos.length;
1152```
1153
1154**`isEmpty()`: determine whether a collection is empty**
1155
1156```javascript
1157var isEmpty = todos.isEmpty();
1158```
1159
1160**`groupBy()`: group a collection into groups of like items**
1161
1162```javascript
1163var todos = new Backbone.Collection();
1164
1165todos.add([
1166  { title: 'go to Belgium.', completed: false },
1167  { title: 'go to China.', completed: false },
1168  { title: 'go to Austria.', completed: true }
1169]);
1170
1171// create groups of completed and incomplete models
1172var byCompleted = todos.groupBy('completed');
1173var completed = new Backbone.Collection(byCompleted[true]);
1174console.log(completed.pluck('title'));
1175// logs: ["go to Austria."]
1176```
1177
1178In addition, several of the Underscore operations on objects are available as methods on Models.
1179
1180**`pick()`: extract a set of attributes from a model**
1181
1182```javascript
1183var Todo = Backbone.Model.extend({
1184  defaults: {
1185    title: '',
1186    completed: false
1187  }
1188});
1189
1190var todo = new Todo({title: 'go to Austria.'});
1191console.log(todo.pick('title'));
1192// logs {title: "go to Austria"}
1193```
1194
1195**`omit()`: extract all attributes from a model except those listed**
1196
1197```javascript
1198var todo = new Todo({title: 'go to Austria.'});
1199console.log(todo.omit('title'));
1200// logs {completed: false}
1201```
1202
1203**`keys()` and `values()`: get lists of attribute names and values**
1204
1205```javascript
1206var todo = new Todo({title: 'go to Austria.'});
1207console.log(todo.keys());
1208// logs: ["title", "completed"]
1209
1210console.log(todo.values());
1211//logs: ["go to Austria.", false]
1212```
1213
1214**`pairs()`: get list of attributes as [key, value] pairs**
1215
1216```javascript
1217var todo = new Todo({title: 'go to Austria.'});
1218var pairs = todo.pairs();
1219
1220console.log(pairs[0]);
1221// logs: ["title", "go to Austria."]
1222console.log(pairs[1]);
1223// logs: ["completed", false]
1224```
1225
1226**`invert()`: create object in which the values are keys and the attributes are values**
1227
1228```javascript
1229var todo = new Todo({title: 'go to Austria.'});
1230console.log(todo.invert());
1231
1232// logs: {'go to Austria.': 'title', 'false': 'completed'}
1233```
1234
1235The complete list of what Underscore can do can be found in its official [documentation](http://documentcloud.github.com/underscore/).
1236
1237#### Chainable API
1238
1239Speaking of utility methods, another bit of sugar in Backbone is its support for Underscore’s `chain()` method. Chaining is a common idiom in object-oriented languages; a chain is a sequence of method calls on the same object that are performed in a single statement. While Backbone makes Underscore's array manipulation operations available as methods of Collection objects, they cannot be directly chained since they return arrays rather than the original Collection.
1240
1241Fortunately, the inclusion of Underscore's `chain()` method enables you to chain calls to these methods on Collections.
1242
1243The `chain()` method returns an object that has all of the Underscore array operations attached as methods which return that object. The chain ends with a call to the `value()` method which simply returns the resulting array value. In case you haven’t seen it before, the chainable API looks like this:
1244
1245```javascript
1246var collection = new Backbone.Collection([
1247  { name: 'Tim', age: 5 },
1248  { name: 'Ida', age: 26 },
1249  { name: 'Rob', age: 55 }
1250]);
1251
1252var filteredNames = collection.chain() // start chain, returns wrapper around collection's models
1253  .filter(function(item) { return item.get('age') > 10; }) // returns wrapped array excluding Tim
1254  .map(function(item) { return item.get('name'); }) // returns wrapped array containing remaining names
1255  .value(); // terminates the chain and returns the resulting array
1256
1257console.log(filteredNames); // logs: ['Ida', 'Rob']
1258```
1259
1260Some of the Backbone-specific methods do return `this`, which means they can be chained as well:
1261
1262```javascript
1263var collection = new Backbone.Collection();
1264
1265collection
1266    .add({ name: 'John', age: 23 })
1267    .add({ name: 'Harry', age: 33 })
1268    .add({ name: 'Steve', age: 41 });
1269
1270var names = collection.pluck('name');
1271
1272console.log(names); // logs: ['John', 'Harry', 'Steve']
1273```
1274
1275## RESTful Persistence
1276
1277Thus far, all of our example data has been created in the browser. For most single page applications, the models are derived from a data store residing on a server. This is an area in which Backbone dramatically simplifies the code you need to write to perform RESTful synchronization with a server through a simple API on its models and collections.
1278
1279**Fetching models from the server**
1280
1281`Collections.fetch()` retrieves a set of models from the server in the form of a JSON array by sending an HTTP GET request to the URL specified by the collection's `url` property (which may be a function). When this data is received, a `set()` will be executed to update the collection.
1282
1283```javascript
1284var Todo = Backbone.Model.extend({
1285  defaults: {
1286    title: '',
1287    completed: false
1288  }
1289});
1290
1291var TodosCollection = Backbone.Collection.extend({
1292  model: Todo,
1293  url: '/todos'
1294});
1295
1296var todos = new TodosCollection();
1297todos.fetch(); // sends HTTP GET to /todos
1298```
1299
1300**Saving models to the server**
1301
1302While Backbone can retrieve an entire collection of models from the server at once, updates to models are performed individually using the model's `save()` method. When `save()` is called on a model that was fetched from the server, it constructs a URL by appending the model's id to the collection's URL and sends an HTTP PUT to the server. If the model is a new instance that was created in the browser (i.e., it doesn't have an id) then an HTTP POST is sent to the collection's URL. `Collections.create()` can be used to create a new model, add it to the collection, and send it to the server in a single method call.
1303
1304```javascript
1305var Todo = Backbone.Model.extend({
1306  defaults: {
1307    title: '',
1308    completed: false
1309  }
1310});
1311
1312var TodosCollection = Backbone.Collection.extend({
1313  model: Todo,
1314  url: '/todos'
1315});
1316
1317var todos = new TodosCollection();
1318todos.fetch();
1319
1320var todo2 = todos.get(2);
1321todo2.set('title', 'go fishing');
1322todo2.save(); // sends HTTP PUT to /todos/2
1323
1324todos.create({title: 'Try out code samples'}); // sends HTTP POST to /todos and adds to collection
1325```
1326
1327As mentioned earlier, a model's `validate()` method is called automatically by `save()` and will trigger an `invalid` event on the model if validation fails.
1328
1329**Deleting models from the server**
1330
1331A model can be removed from the containing collection and the server by calling its `destroy()` method. Unlike `Collection.remove()` which only removes a model from a collection, `Model.destroy()` will also send an HTTP DELETE to the collection's URL.
1332
1333```javascript
1334var Todo = Backbone.Model.extend({
1335  defaults: {
1336    title: '',
1337    completed: false
1338  }
1339});
1340
1341var TodosCollection = Backbone.Collection.extend({
1342  model: Todo,
1343  url: '/todos'
1344});
1345
1346var todos = new TodosCollection();
1347todos.fetch();
1348
1349var todo2 = todos.get(2);
1350todo2.destroy(); // sends HTTP DELETE to /todos/2 and removes from collection
1351```
1352
1353Calling `destroy` on a Model will return `false` if the model `isNew`:
1354
1355```javascript
1356var todo = new Backbone.Model();
1357console.log(todo.destroy());
1358// false
1359```
1360
1361**Options**
1362
1363Each RESTful API method accepts a variety of options. Most importantly, all methods accept success and error callbacks which can be used to customize the handling of server responses. 
1364
1365Specifying the `{patch: true}` option to `Model.save()` will cause it to use HTTP PATCH to send only the changed attributes (i.e partial updates) to the server instead of the entire model i.e `model.save(attrs, {patch: true})`:
1366
1367```javascript
1368// Save partial using PATCH
1369model.clear().set({id: 1, a: 1, b: 2, c: 3, d: 4});
1370model.save();
1371model.save({b: 2, d: 4}, {patch: true});
1372console.log(this.syncArgs.method);
1373// 'patch'
1374```
1375
1376Similarly, passing the `{reset: true}` option to `Collection.fetch()` will result in the collection being updated using `reset()` rather than `set()`.
1377
1378See the Backbone.js documentation for full descriptions of the supported options.
1379
1380## Events
1381
1382Events are a basic inversion of control. Instead of having one function call another by name, the second function is registered as a handler to be called when a specific event occurs.
1383
1384The part of your application that has to know how to call the other part of your app has been inverted. This is the core thing that makes it possible for your business logic to not have to know about how your user interface works and is the most powerful thing about the Backbone Events system.
1385
1386Mastering events is one of the quickest ways to become more productive with Backbone, so let's take a closer look at Backbone's event model.
1387
1388`Backbone.Events` is mixed into the other Backbone "classes", including:
1389
1390* Backbone
1391* Backbone.Model
1392* Backbone.Collection
1393* Backbone.Router
1394* Backbone.History
1395* Backbone.View
1396
1397Note that `Backbone.Events` is mixed into the `Backbone` object. Since `Backbone` is globally visible, it can be used as a simple event bus:
1398
1399```javascript
1400Backbone.on('event', function() {console.log('Handled Backbone event');});
1401Backbone.trigger('event'); // logs: Handled Backbone event
1402```
1403
1404#### on(), off(), and trigger()
1405
1406`Backbone.Events` can give any object the ability to bind and trigger custom events. We can mix this module into any object easily and there isn't a requirement for events to be declared before being bound to a callback handler.
1407
1408Example:
1409
1410```javascript
1411var ourObject = {};
1412
1413// Mixin
1414_.extend(ourObject, Backbone.Events);
1415
1416// Add a custom event
1417ourObject.on('dance', function(msg){
1418  console.log('We triggered ' + msg);
1419});
1420
1421// Trigger the custom event
1422ourObject.trigger('dance', 'our event');
1423```
1424
1425If you're familiar with jQuery custom events or the concept of Publish/Subscribe, `Backbone.Events` provides a system that is very similar with `on` being analogous to `subscribe` and `trigger` being similar to `publish`.
1426
1427`on` binds a callback function to an object, as we've done with `dance` in the above example. The callback is invoked whenever the event is triggered.
1428
1429The official Backbone.js documentation recommends namespacing event names using colons if you end up using quite a few of these on your page. e.g.:
1430
1431```javascript
1432var ourObject = {};
1433
1434// Mixin
1435_.extend(ourObject, Backbone.Events);
1436
1437function dancing (msg) { console.log("We started " + msg); }
1438
1439// Add namespaced custom events
1440ourObject.on("dance:tap", dancing);
1441ourObject.on("dance:break", dancing);
1442
1443// Trigger the custom events
1444ourObject.trigger("dance:tap", "tap dancing. Yeah!");
1445ourObject.trigger("dance:break", "break dancing. Yeah!");
1446
1447// This one triggers nothing as no listener listens for it
1448ourObject.trigger("dance", "break dancing. Yeah!");
1449```
1450
1451A special `all` event is made available in case you would like notifications for every event that occurs on the object (e.g., if you would like to screen events in a single location). The `all` event can be used as follows:
1452
1453
1454```javascript
1455var ourObject = {};
1456
1457// Mixin
1458_.extend(ourObject, Backbone.Events);
1459
1460function dancing (msg) { console.log("We started " + msg); }
1461
1462ourObject.on("all", function(eventName){
1463  console.log("The name of the event passed was " + eventName);
1464});
1465
1466// This time each event will be caught with a catch 'all' event listener
1467ourObject.trigger("dance:tap", "tap dancing. Yeah!");
1468ourObject.trigger("dance:break", "break dancing. Yeah!");
1469ourObject.trigger("dance", "break dancing. Yeah!");
1470```
1471
1472`off` removes callback functions that were previously bound to an object. Going back to our Publish/Subscribe comparison, think of it as an `unsubscribe` for custom events.
1473
1474To remove the `dance` event we previously bound to `ourObject`, we would simply do:
1475
1476```javascript
1477var ourObject = {};
1478
1479// Mixin
1480_.extend(ourObject, Backbone.Events);
1481
1482function dancing (msg) { console.log("We " + msg); }
1483
1484// Add namespaced custom events
1485ourObject.on("dance:tap", dancing);
1486ourObject.on("dance:break", dancing);
1487
1488// Trigger the custom events. Each will be caught and acted upon.
1489ourObject.trigger("dance:tap", "started tap dancing. Yeah!");
1490ourObject.trigger("dance:break", "started break dancing. Yeah!");
1491
1492// Removes event bound to the object
1493ourObject.off("dance:tap");
1494
1495// Trigger the custom events again, but one is logged.
1496ourObject.trigger("dance:tap", "stopped tap dancing."); // won't be logged as it's not listened for
1497ourObject.trigger("dance:break", "break dancing. Yeah!");
1498```
1499
1500To remove all callbacks for the event we pass an event name (e.g., `move`) to the `off()` method on the object the event is bound to. If we wish to remove a specific callback, we can pass that callback as the second parameter:
1501
1502```javascript
1503var ourObject = {};
1504
1505// Mixin
1506_.extend(ourObject, Backbone.Events);
1507
1508function dancing (msg) { console.log("We are dancing. " + msg); }
1509function jumping (msg) { console.log("We are jumping. " + msg); }
1510
1511// Add two listeners to the same event
1512ourObject.on("move", dancing);
1513ourObject.on("move", jumping);
1514
1515// Trigger the events. Both listeners are called.
1516ourObject.trigger("move", "Yeah!");
1517
1518// Removes specified listener
1519ourObject.off("move", dancing);
1520
1521// Trigger the events again. One listener left.
1522ourObject.trigger("move", "Yeah, jump, jump!");
1523```
1524
1525Finally, as we have seen in our previous examples, `trigger` triggers a callback for a specified event (or a space-separated list of events). e.g.:
1526
1527```javascript
1528var ourObject = {};
1529
1530// Mixin
1531_.extend(ourObject, Backbone.Events);
1532
1533function doAction (msg) { console.log("We are " + msg); }
1534
1535// Add event listeners
1536ourObject.on("dance", doAction);
1537ourObject.on("jump", doAction);
1538ourObject.on("skip", doAction);
1539
1540// Single event
1541ourObject.trigger("dance", 'just dancing.');
1542
1543// Multiple events
1544ourObject.trigger("dance jump skip", 'very tired from so much action.');
1545```
1546
1547`trigger` can pass multiple arguments to the callback function:
1548
1549```javascript
1550var ourObject = {};
1551
1552// Mixin
1553_.extend(ourObject, Backbone.Events);
1554
1555function doAction (action, duration) {
1556  console.log("We are " + action + ' for ' + duration ); 
1557}
1558
1559// Add event listeners
1560ourObject.on("dance", doAction);
1561ourObject.on("jump", doAction);
1562ourObject.on("skip", doAction);
1563
1564// Passing multiple arguments to single event
1565ourObject.trigger("dance", 'dancing', "5 minutes");
1566
1567// Passing multiple arguments to multiple events
1568ourObject.trigger("dance jump skip", 'on fire', "15 minutes");
1569```
1570
1571#### listenTo() and stopListening()
1572
1573While `on()` and `off()` add callbacks directly to an observed object, `listenTo()` tells an object to listen for events on another object, allowing the listener to keep track of the events for which it is listening. `stopListening()` can subsequently be called on the listener to tell it to stop listening for events:
1574
1575```javascript
1576var a = _.extend({}, Backbone.Events);
1577var b = _.extend({}, Backbone.Events);
1578var c = _.extend({}, Backbone.Events);
1579
1580// add listeners to A for events on B and C
1581a.listenTo(b, 'anything', function(event){ console.log("anything happened"); });
1582a.listenTo(c, 'everything', function(event){ console.log("everything happened"); });
1583
1584// trigger an event
1585b.trigger('anything'); // logs: anything happened
1586
1587// stop listening
1588a.stopListening();
1589
1590// A does not receive these events
1591b.trigger('anything');
1592c.trigger('everything');
1593```
1594
1595`stopListening()` can also be used to selectively stop listening based on the event, model, or callback handler.
1596
1597If you use `on` and `off` and remove views and their corresponding models at the same time, there are generally no problems. But a problem arises when you remove a view that had registered to be notified about events on a model, but you don't remove the model or call `off` to remove the view's event handler. Since the model has a reference to the view's callback function, the JavaScript garbage collector cannot remove the view from memory. This is called a "ghost view" and is a form of memory leak which is common since the models generally tend to outlive the corresponding views during an application's lifecycle. For details on the topic and a solution, check this [excellent article](http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/) by Derick Bailey. 
1598
1599Practically, every `on` called on an object also requires an `off` to be called in order for the garbage collector to do its job. `listenTo()` changes that, allowing Views to bind to Model notifications and unbind from all of them with just one call - `stopListening()`.
1600
1601The default implementation of `View.remove()` makes a call to `stopListening()`, ensuring that any listeners bound using `listenTo()` are unbound before the view is destroyed.
1602
1603```javascript
1604var view = new Backbone.View();
1605var b = _.extend({}, Backbone.Events);
1606
1607view.listenTo(b, 'all', function(){ console.log(true); });
1608b.trigger('anything');  // logs: true
1609
1610view.listenTo(b, 'all', function(){ console.log(false); });
1611view.remove(); // stopListening() implicitly called
1612b.trigger('anything');  // does not log anything
1613```
1614
1615#### Events and Views
1616
1617Within a View, there are two types of events you can listen for: DOM events and events triggered using the Event API. It is important to understand the differences in how views bind to these events and the context in which their callbacks are invoked.
1618
1619DOM events can be bound to using the View's `events` property or using `jQuery.on()`. Within callbacks bound using the `events` property, `this` refers to the View object; whereas any callbacks bound directly using jQuery will have `this` set to the handling DOM element by jQuery. All DOM event callbacks are passed an `event` object by jQuery. See `delegateEvents()` in the Backbone documentation for additional details.
1620
1621Event API events are bound as described in this section. If the event is bound using `on()` on the observed object, a context parameter can be passed as the third argument. If the event is bound using `listenTo()` then within the callback `this` refers to the listener. The arguments passed to Event API callbacks depends on the type of event. See the Catalog of Events in the Backbone documentation for details.
1622
1623The following example illustrates these differences:
1624
1625```html
1626<div id="todo">
1627    <input type='checkbox' />
1628</div>
1629```
1630
1631```javascript
1632var View = Backbone.View.extend({
1633
1634    el: '#todo',
1635
1636    // bind to DOM event using events property
1637    events: {
1638        'click [type="checkbox"]': 'clicked',
1639    },
1640
1641    initialize: function () {
1642        // bind to DOM event using jQuery
1643        this.$el.click(this.jqueryClicked);
1644
1645        // bind to API event
1646        this.on('apiEvent', this.callback);
1647    },
1648
1649    // 'this' is view
1650    clicked: function(event) {
1651        console.log("events handler for " + this.el.outerHTML);
1652        this.trigger('apiEvent', event.type);
1653    },
1654
1655    // 'this' is handling DOM element
1656    jqueryClicked: function(event) {
1657        console.log("jQuery handler for " + this.outerHTML);
1658    },
1659
1660    callback: function(eventType) {
1661        console.log("event type was " + eventType);
1662    }
1663
1664});
1665
1666var view = new View();
1667```
1668
1669## Routers
1670
1671In Backbone, routers provide a way for you to connect URLs (either hash fragments, or
1672real) to parts of your application. Any piece of your application that you want
1673to be bookmarkable, shareable, and back-button-able, needs a URL.
1674
1675Some examples of routes using the hash mark may be seen below:
1676
1677```javascript
1678http://example.com/#about
1679http://example.com/#search/seasonal-horns/page2
1680```
1681
1682An application will usually have at least one route mapping a URL route to a function that determines what happens when a user reaches that route. This relationship is defined as follows:
1683
1684```javascript
1685'route' : 'mappedFunction'
1686```
1687
1688Let's define our first router by extending `Backbone.Router`. For the purposes of this guide, we're going to continue pretending we're creating a complex todo application (something like a personal organizer/planner) that requires a complex TodoRouter.
1689
1690Note the inline comments in the code example below as they continue our lesson on routers.
1691
1692```javascript
1693var TodoRouter = Backbone.Router.extend({
1694    /* define the route and function maps for this router */
1695    routes: {
1696        "about" : "showAbout",
1697        /* Sample usage: http://example.com/#about */
1698
1699        "todo/:id" : "getTodo",
1700        /* This is an example of using a ":param" variable which allows us to match
1701        any of the components between two URL slashes */
1702        /* Sample usage: http://example.com/#todo/5 */
1703
1704        "search/:query" : "searchTodos",
1705        /* We can also define multiple routes that are bound to the same map function,
1706        in this case searchTodos(). Note below how we're optionally passing in a
1707        reference to a page number if one is supplied */
1708        /* Sample usage: http://example.com/#search/job */
1709
1710        "search/:query/p:page" : "searchTodos",
1711        /* As we can see, URLs may contain as many ":param"s as we wish */
1712        /* Sample usage: http://example.com/#search/job/p1 */
1713
1714        "todos/:id/download/*documentPath" : "downloadDocument",
1715        /* This is an example of using a *splat. Splats are able to match any number of
1716        URL components and can be combined with ":param"s*/
1717        /* Sample usage: http://example.com/#todos/5/download/files/Meeting_schedule.doc */
1718
1719        /* If you wish to use splats for anything beyond default routing, it's probably a good
1720        idea to leave them at the end of a URL otherwise you may need to apply regular
1721        expression parsing on your fragment */
1722
1723        "*other"    : "defaultRoute",
1724        /* This is a default route that also uses a *splat. Consider the
1725        default route a wildcard for URLs that are either not matched or where
1726        the user has incorrectly typed in a route path manually */
1727        /* Sample usage: http://example.com/# <anything> */
1728
1729        "optional(/:item)": "optionalItem",
1730        "named/optional/(y:z)": "namedOptionalItem"
1731        /* Router URLs also support optional parts via parentheses, without having
1732           to use a regex.  */
1733    },
1734
1735    showAbout: function(){
1736    },
1737
1738    getTodo: function(id){
1739        /*
1740        Note that the id matched in the above route will be passed to this function
1741        */
1742        console.log("You are trying to reach todo " + id);
1743    },
1744
1745    searchTodos: function(query, page){
1746        var page_number = page || 1;
1747        console.log("Page number: " + page_number + " of the results for todos containing the word: " + query);
1748    },
1749
1750    downloadDocument: function(id, path){
1751    },
1752
1753    defaultRoute: function(other){
1754        console.log('Invalid. You attempted to reach:' + other);
1755    }
1756});
1757
1758/* Now that we have a router setup, we need to instantiate it */
1759
1760var myTodoRouter = new TodoRouter();
1761```
1762
1763
1764Backbone offers an opt-in for HTML5 pushState support via `window.history.pushState`. This permits you to define routes such as http://backbonejs.org/just/an/example. This will be supported with automatic degradation when a user's browser doesn't support pushState. Note that it is vastly preferred if you're capable of also supporting pushState on the server side, although it is a little more difficult to implement.
1765
1766**Is there a limit to the number of routers I should be using?**
1767
1768Andrew de Andrade has pointed out that DocumentCloud, the creators of Backbone, usually only use a single router in most of their applications. You're very likely to not require more than one or two routers in your own projects; the majority of your application routing can be kept organized in a single router without it getting unwieldy.
1769
1770#### Backbone.history
1771
1772Next, we need to initialize `Backbone.history` as it handles `hashchange` events in our application. This will automatically handle routes that have been defined and trigger callbacks when they've been accessed.
1773
1774The `Backbone.history.start()` method will simply tell Backbone that it's okay to begin monitoring all `hashchange` events as follows:
1775
1776```javascript
1777var TodoRouter = Backbone.Router.extend({
1778  /* define the route and function maps for this router */
1779  routes: {
1780    "about" : "showAbout",
1781    "search/:query" : "searchTodos",
1782    "search/:query/p:page" : "searchTodos"
1783  },
1784
1785  showAbout: function(){},
1786
1787  searchTodos: function(query, page){
1788    var page_number = page || 1;
1789    console.log("Page number: " + page_number + " of the results for todos containing the word: " + query);
1790  }
1791});
1792
1793var myTodoRouter = new TodoRouter();
1794
1795Backbone.history.start();
1796
1797// Go to and check console:
1798// http://localhost/#search/job/p3   logs: Page number: 3 of the results for todos containing the word: job
1799// http://localhost/#search/job      logs: Page number: 1 of the results for todos containing the word: job 
1800// etc.
1801```
1802
1803Note: To run the last example, you'll need to create a local development environment and test project, which we will cover later on in the book.
1804
1805If you would like to update the URL to reflect the application state at a particular point, you can use the router's `.navigate()` method. By default, it simply updates your URL fragment without triggering the `hashchange` event:
1806
1807```javascript
1808// Let's imagine we would like a specific fragment (edit) once a user opens a single todo
1809var TodoRouter = Backbone.Router.extend({
1810  routes: {
1811    "todo/:id": "viewTodo",
1812    "todo/:id/edit": "editTodo"
1813    // ... other routes
1814  },
1815
1816  viewTodo: function(id){
1817    console.log("View todo requested.");
1818    this.navigate("todo/" + id + '/edit'); // updates the fragment for us, but doesn't trigger the route
1819  },
1820
1821  editTodo: function(id) {
1822    console.log("Edit todo opened.");
1823  }
1824});
1825
1826var myTodoRouter = new TodoRouter();
1827
1828Backbone.history.start();
1829
1830// Go to: http://localhost/#todo/4
1831//
1832// URL is updated to: http://localhost/#todo/4/edit
1833// but editTodo() function is not invoked even though location we end up is mapped to it.
1834//
1835// logs: View todo requested.
1836```
1837
1838It is also possible for `Router.navigate()` to trigger the route along with updating the URL fragment by passing the `trigger:true` option.
1839
1840Note: This usage is discouraged. The recommended usage is the one described above which creates a bookmarkable URL when your application transitions to a specific state.
1841
1842```javascript
1843var TodoRouter = Backbone.Router.extend({
1844  routes: {
1845    "todo/:id": "viewTodo",
1846    "todo/:id/edit": "editTodo"
1847    // ... other routes
1848  },
1849
1850  viewTodo: function(id){
1851    console.log("View todo requested.");
1852    this.navigate("todo/" + id + '/edit', {trigger: true}); // updates the fragment and triggers the route as well
1853  },
1854
1855  editTodo: function(id) {
1856    console.log("Edit todo opened.");
1857  }
1858});
1859
1860var myTodoRouter = new TodoRouter();
1861
1862Backbone.history.start();
1863
1864// Go to: http://localhost/#todo/4
1865//
1866// URL is updated to: http://localhost/#todo/4/edit
1867// and this time editTodo() function is invoked.
1868//
1869// logs:
1870// View todo requested.
1871// Edit todo opened.
1872```
1873
1874A "route" event is also triggered on the router in addition to being fired on Backbone.history.
1875
1876```javascript
1877Backbone.history.on('route', onRoute);
1878
1879// Trigger 'route' event on router instance.
1880router.on('route', function(name, args) {
1881  console.log(name === 'routeEvent'); 
1882});
1883
1884location.replace('http://example.com#route-event/x');
1885Backbone.history.checkUrl();
1886```
1887
1888## Backbone’s Sync API
1889
1890We previously discussed how Backbone supports RESTful persistence via its `fetch()` and `create()` methods on Collections and `save()`, and `destroy()` methods on Models. Now we are going to take a closer look at Backbone's sync method which underlies these operations.
1891
1892The Backbone.sync method is an integral part of Backbone.js. It assumes a jQuery-like `$.ajax()` method, so HTTP parameters are organized based on jQuery’s API. Since some legacy servers may not support JSON-formatted requests and HTTP PUT and DELETE operations, Backbone can be configured to emulate these capabilities using the two configuration variables shown below with their default values:
1893
1894```javascript
1895Backbone.emulateHTTP = false; // set to true if server cannot handle HTTP PUT or HTTP DELETE
1896Backbone.emulateJSON = false; // set to true if server cannot handle application/json requests
1897```
1898
1899The inline Backbone.emulateHTTP option should be set to true if extended HTTP methods are not supported by the server. The Backbone.emulateJSON option should be set to true if the server does not understand the MIME type for JSON.
1900
1901```javascript
1902// Create a new library collection
1903var Library = Backbone.Collection.extend({
1904    url : function() { return '/library'; }
1905});
1906
1907// Define attributes for our model
1908var attrs = {
1909    title  : "The Tempest",
1910    author : "Bill Shakespeare",
1911    length : 123
1912};
1913  
1914// Create a new Library instance
1915var library = new Library;
1916
1917// Create a new instance of a model within our collection
1918library.create(attrs, {wait: false});
1919  
1920// Update with just emulateHTTP
1921library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, {
1922  emulateHTTP: true
1923});
1924    
1925// Check the ajaxSettings being used for our request
1926console.log(this.ajaxSettings.url === '/library/2-the-tempest'); // true
1927console.log(this.ajaxSettings.type === 'POST'); // true
1928console.log(this.ajaxSettings.contentType === 'application/json'); // true
1929
1930// Parse the data for the request to confirm it is as expected
1931var data = JSON.parse(this.ajaxSettings.data);
1932console.log(data.id === '2-the-tempest');  // true
1933console.log(data.author === 'Tim Shakespeare'); // true
1934console.log(data.length === 123); // true
1935```
1936
1937Similarly, we could just update using `emulateJSON`:
1938
1939```javascript
1940library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, {
1941  emulateJSON: true
1942});
1943
1944console.log(this.ajaxSettings.url === '/library/2-the-tempest'); // true
1945console.log(this.ajaxSettings.type === 'PUT'); // true
1946console.log(this.ajaxSettings.contentType ==='application/x-www-form-urlencoded'); // true
1947
1948var data = JSON.parse(this.ajaxSettings.data.model);
1949console.log(data.id === '2-the-tempest');
1950console.log(data.author ==='Tim Shakespeare');
1951console.log(data.length === 123);
1952```
1953
1954`Backbone.sync` is called every time Backbone tries to read, save, or delete models. It uses jQuery or Zepto's `$.ajax()` implementations to make these RESTful requests, however this can be overridden as per your needs.
1955
1956**Overriding Backbone.sync**
1957
1958The `sync` function may be overridden globally as Backbone.sync, or at a finer-grained level, by adding a sync function to a Backbone collection or to an individual model.
1959
1960Since all persistence is handled by the Backbone.sync function, an alternative persistence layer can be used by simply overriding Backbone.sync with a function that has the same signature:
1961
1962```javascript
1963Backbone.sync = function(method, model, options) {
1964};
1965```
1966
1967The methodMap below is used by the standard sync implementation to map the method parameter to an HTTP operation and illustrates the type of action required by each method argument:
1968
1969```javascript
1970var methodMap = {
1971  'create': 'POST',
1972  'update': 'PUT',
1973  'patch':  'PATCH',
1974  'delete': 'DELETE',
1975  'read':   'GET'
1976};
1977```
1978
1979If we wanted to replace the standard `sync` implementation with one that simply logged the calls to sync, we could do this:
1980
1981```javascript
1982var id_counter = 1;
1983Backbone.sync = function(method, model) {
1984  console.log("I've been passed " + method + " with " + JSON.stringify(model));
1985  if(method === 'create'){ model.set('id', id_counter++); }
1986};
1987```
1988
1989Note that we assign a unique id to any created models.
1990
1991The Backbone.sync method is intended to be overridden to support other persistence backends. The built-in method is tailored to a certain breed of RESTful JSON APIs - Backbone was originally extracted from a Ruby on Rails application, which uses HTTP methods like PUT in the same way.
1992
1993The sync method is called with three parameters:
1994
1995* method: One of create, update, patch, delete, or read
1996* model: The Backbone model object
1997* options: May include success and error methods
1998
1999Implementing a new sync method can use the following pattern:
2000
2001```javascript
2002Backbone.sync = function(method, model, options) {
2003
2004  function success(result) {
2005    // Handle successful results from MyAPI
2006    if (options.success) {
2007      options.success(result);
2008    }
2009  }
2010
2011  function error(result) {
2012    // Handle error results from MyAPI
2013    if (options.error) {
2014      options.error(result);
2015    }
2016  }
2017
2018  options || (options = {});
2019
2020  switch (method) {
2021    case 'create':
2022      return MyAPI.create(model, success, error);
2023
2024    case 'update':
2025      return MyAPI.update(model, success, error);
2026
2027    case 'patch':
2028      return MyAPI.patch(model, success, error);
2029
2030    case 'delete':
2031      return MyAPI.destroy(model, success, error);
2032
2033    case 'read':
2034      if (model.cid) {
2035        return MyAPI.find(model, success, error);
2036      } else {
2037        return MyAPI.findAll(model, success, error);
2038      }
2039  }
2040};
2041```
2042
2043This pattern delegates API calls to a new object (MyAPI), which could be a Backbone-style class that supports events. This can be safely tested separately, and potentially used with libraries other than Backbone.
2044
2045There are quite a few sync implementations out there. The following examples are all available on GitHub:
2046
2047* Backbone localStorage: persists to the browser's local storage
2048* Backbone offline: supports working offline
2049* Backbone Redis: uses Redis key-value store
2050* backbone-parse: integrates Backbone with Parse.com
2051* backbone-websql: stores data to WebSQL
2052* Backbone Caching Sync: uses local storage as cache for other sync implementations
2053
2054
2055## Dependencies
2056
2057The official Backbone.js [documentation](http://backbonejs.org/) states:
2058
2059>Backbone's only hard dependency is either Underscore.js ( >= 1.4.3) or Lo-Dash. For RESTful persistence, history support via Backbone.Router and DOM manipulation with Backbone.View, include json2.js, and either jQuery ( >= 1.7.0) or Zepto.
2060
2061What this translates to is that if you require working with anything beyond models, you will need to include a DOM manipulation library such as jQuery or Zepto. Underscore is primarily used for its utility methods (which Backbone relies upon heavily) and json2.js for legacy browser JSON support if Backbone.sync is used.
2062
2063## Summary
2064
2065In this chapter we have introduced you to the components you will be using to build applications with Backbone: Models, Views, Collections, and Routers. We've also explored the Events mix-in that Backbone uses to enhance all components with publish-subscribe capabilities and seen how it can be used with arbitrary objects. Finally, we saw how Backbone leverages the Underscore.js and jQuery/Zepto APIs to add rich manipulation and persistence features to Backbone Collections and Models.
2066
2067Backbone has many operations and options beyond those we have covered here and is always evolving, so be sure to visit the official [documentation](http://backbonejs.org/) for more details and the latest features. In the next chapter you will start to get your hands dirty as we walk you through the implementation of your first Backbone application.
2068
2069