PageRenderTime 113ms CodeModel.GetById 3ms app.highlight 97ms RepoModel.GetById 1ms app.codeStats 1ms

/chapters/03-internals.md

https://github.com/1st/backbone-fundamentals
Markdown | 2069 lines | 1503 code | 566 blank | 0 comment | 0 complexity | 9996058cb12855bdcd822bc6a085fe69 MD5 | raw file

Large files files are truncated, but you can click here to view the full 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/Linux, 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 set 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` ob…

Large files files are truncated, but you can click here to view the full file