Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding some initial contribs from dailyjs, to be better positioned an…

…d fleshed out later.
  • Loading branch information...
commit 2315aef82f42b7e3c2664ca5fc2ef17dbab99f18 1 parent 8ad3372
@addyosmani authored
View
BIN  backbone-fundamentals.epub
Binary file not shown
View
226 backbone-fundamentals.rtf
@@ -396,7 +396,7 @@ Taligent
{\pard \ql \f0 \sa180 \li0 \fi0 Although a common implementation of a {\field{\*\fldinst{HYPERLINK "http://martinfowler.com/eaaDev/PassiveScreen.html"}}{\fldrslt{\ul
Passive View
}}}
- is for the view to implement an interface, there are variations on it, including the use of events which can decouple the View from the Presenter a little more. As we don\u8217't have the interface construct in JavaScript, we\u8217're using it more as more a protocol than an explicit interface here. It\u8217's technically still an API and it\u8217's probably fair for us to refer to it as an interface from that perspective.\par}
+ is for the view to implement an interface, there are variations on it, including the use of events which can decouple the View from the Presenter a little more. As we don\u8217't have the interface construct in JavaScript, we\u8217're using it more and more a protocol than an explicit interface here. It\u8217's technically still an API and it\u8217's probably fair for us to refer to it as an interface from that perspective.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 There is also a {\field{\*\fldinst{HYPERLINK "http://martinfowler.com/eaaDev/SupervisingPresenter.html"}}{\fldrslt{\ul
Supervising Controller
}}}
@@ -497,6 +497,11 @@ this
{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Decouple the DOM from your page\u8217's data\par}
{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Model data, views and routers in a succinct manner\par}
{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Provide DOM, model and collection synchronization\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Is Backbone right for you?\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Does the following describe you?:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 "I want something flexible which offers a minimalist solution to separating concerns in my application. It should support a persistence layer and RESTful sync, models, views (with controllers), event-driven communication, templating and routing. It should be imperative, allowing one to update the View when a model changes. I\u8217'd like some decisions about the architecture left up to me. Ideally, many large companies have used the solution to build non-trivial applications.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 As I may be building something complex, I\u8217'd like there to be an active extension community around the framework that have already tried addressing larger problems (Marionette, Chaplin, Aura, Thorax). Ideally, there are also scaffolding tools (grunt-bbb, brunch) available for the solution."\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 If so, continue reading.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 The Basics\par}
{\pard \ql \f0 \sa180 \li0 \fi0 In this section, you\u8217'll learn the essentials of Backbone\u8217's models, views, collections and routers, as well as about using namespacing to organize your code. This isn\u8217't meant as a replacement for the official documentation, but it will help you understand many of the core concepts behind Backbone before you start building applications with it.\par}
{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Models\par}
@@ -735,14 +740,29 @@ PhotoCollection.add([\line
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 var PhotoCollection = new Backbone.Collection;\line
PhotoCollection.url = '/photos';\line
PhotoCollection.fetch();\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Under the covers, {\f1 Backbone.sync} is the function called every time Backbone tries to read or save models to the server. It uses jQuery or Zepto\u8217's ajax implementations to make these RESTful requests, however this can be overridden as per your needs.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 During configuration, Backbone sets a variable to denote if extended HTTP methods are supported by the server. Another setting controls if the server understands the correct MIME type for JSON:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 Backbone.emulateHTTP = false;\line
+Backbone.emulateJSON = false;\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 The Backbone.sync method that uses these values is actually an integral part of Backbone.js. A jQuery-like ajax method is assumed, so HTTP parameters are organised based on jQuery\u8217's API. Searching through the code for calls to the sync method show it\u8217's used whenever a model is saved, fetched, or deleted (destroyed).\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Under the covers, {\f1 Backbone.sync} is the function called every time Backbone tries to read or save models to the server. It uses jQuery or Zepto\u8217's ajax implementations to make these RESTful requests, however this can be overridden as per your needs. :\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 The sync function may be overriden globally as Backbone.sync, or at a finer-grained level, by adding a sync function to a Backbone collection or to an individual model.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 There\u8217's no fancy plugin API for adding a persistence layer \u8211- simply override Backbone.sync with the same function signature:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 Backbone.sync = function(method, model, options) \{\line
+\};\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 The default methodMap is useful for working out what the method argument does:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 var methodMap = \{\line
+ 'create': 'POST',\line
+ 'update': 'PUT',\line
+ 'delete': 'DELETE',\line
+ 'read': 'GET'\line
+\};\par}
{\pard \ql \f0 \sa180 \li0 \fi0 In the above example if we wanted to log an event when {\f1 .sync()} was called, we could do this:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 Backbone.sync = function(method, model) \{\line
console.log("I've been passed " + method + " with " + JSON.stringify(model));\line
\};\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Resetting/Refreshing Collections}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Rather than adding or removing models individually, you might occasionally wish to update an entire collection at once. {\f1 Collection.reset()} allows us to replace an entire collection with new models as follows:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\f1 javascript PhotoCollection.reset([ \{title: "My trip to Scotland", src: "scotland-trip.jpg"\}, \{title: "The flight from Scotland", src: "long-flight.jpg"\}, \{title: "Latest snap of lock-ness", src: "lockness.jpg"\}]);} Note that using {\f1 Collection.reset()} doesn\u8217't fire any {\f1 add} or {\f1 remove} events. A {\f1 reset} event is fired instead.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\f1 javascript PhotoCollection.reset([ \{title: "My trip to Scotland", src: "scotland-trip.jpg"\}, \{title: "The flight from Scotland", src: "long-flight.jpg"\}, \{title: "Latest snap of Loch Ness", src: "lochness.jpg"\}]);} Note that using {\f1 Collection.reset()} doesn\u8217't fire any {\f1 add} or {\f1 remove} events. A {\f1 reset} event is fired instead.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Underscore utility functions\par}
{\pard \ql \f0 \sa180 \li0 \fi0 As Backbone requires Underscore as a hard dependency, we\u8217're able to use many of the utilities it has to offer to aid with our application development. Here\u8217's an example of how Underscore\u8217's {\f1 sortBy()} method can be used to sort a collection of photos based on a particular attribute.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 var sortedByAlphabet = PhotoCollection.sortBy(function (photo) \{\line
@@ -841,6 +861,150 @@ zoomPhoto: function(factor)\{\line
this.zoom(factor); //imagine this zooms into the image\line
this.navigate("zoom/" + factor, true); //updates the fragment for us and triggers the route\line
\}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Chainable API\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Another bit of sugar is the support for Underscore\u8217's chain method. This works by calling the original method with the current array of models and returning the result. In case you haven\u8217't seen it before, the chainable API looks like this:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 var collection = new Backbone.Collection([\line
+ \{ name: 'Tim', age: 5 \},\line
+ \{ name: 'Ida', age: 26 \},\line
+ \{ name: 'Rob', age: 55 \}\line
+]);\line
+\line
+collection.chain()\line
+ .filter(function(item) \{ return item.get('age') > 10; \})\line
+ .map(function(item) \{ return item.get('name'); \})\line
+ .value();\line
+\line
+// Will return ['Ida', 'Rob']\line
+Some of the Backbone-specific method will return this, which means they can be chained as well:\line
+\line
+var collection = new Backbone.Collection();\line
+\line
+collection\line
+ .add(\{ name: 'John', age: 23 \})\line
+ .add(\{ name: 'Harry', age: 33 \})\line
+ .add(\{ name: 'Steve', age: 41 \});\line
+\line
+collection.pluck('name');\line
+// ['John', 'Harry', 'Steve']\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Backbone\u8217's inheritance Implementation\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 The comments indicate that the inherits function is inspired by goog.inherits. Google\u8217's implementation is from the Closure Library, but Backbone\u8217's API accepts two objects (incorrectly referred to as a hash) containing \u8220"instance\u8221" and \u8220"static\u8221" methods. Each of Backbone\u8217's objects has an extend method:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Model.extend = Collection.extend = Router.extend = View.extend = extend; Most development with Backbone is based around inheriting from these objects, and they\u8217're designed to mimic a classical object-oriented implementation.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Backbone uses Underscore\u8217's extend method:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 each(slice.call(arguments, 1), function(source) \{\line
+ for (var prop in source) \{\line
+ obj[prop] = source[prop];\line
+ \}\line
+\});\line
+\line
+return obj;\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This isn\u8217't the same as ES5\u8217's Object.create, it\u8217's actually copying properties (methods and values) from one object to another. Since this isn\u8217't enough to support Backbone\u8217's inheritance and class model, the following steps are performed:\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab The instance methods are checked to see if there\u8217's a constructor property. If so, the class\u8217's constructor is used, otherwise the parent\u8217's constructor is used (i.e., Backbone.Model)\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Underscore\u8217's extend method is called to add the parent class\u8217's methods to the new child class The prototype property of a blank constructor function is assigned with the parent\u8217's prototype, and a new instance of this is set to the child\u8217's prototype property\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab Underscore\u8217's extend method is called twice to add the static and instance methods to the child class\par}
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab The child\u8217's prototype\u8217's constructor and a {\b super} property are assigned\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This pattern is also used for classes in CoffeeScript, so Backbone classes are compatible with CoffeeScript classes.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Backbone\u8217's Sync API\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 The Backbone.sync method is intended to be overridden to support other backends. The built-in method is tailed to a certain breed of RESTful JSON APIs \u8211- Backbone was originally extracted from a Ruby on Rails application, which uses HTTP methods like PUT the same way.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 The way this works is the model and collection classes have a sync method that calls Backbone.sync. Both will call this.sync internally when fetching, saving, or deleting items.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 The sync method is called with three parameters:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab method: One of create, update, delete, read\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab model: The Backbone model object\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab options: May include success and error methods\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Implementing a new sync method can use the following pattern:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 Backbone.sync = function(method, model, options) \{\line
+ var requestContent = \{\}, success, error;\line
+\line
+ function success(result) \{\line
+ // Handle results from MyAPI\line
+ if (options.success) \{\line
+ options.success(result);\line
+ \}\line
+ \}\line
+\line
+ function error(result) \{\line
+ // Handle results from MyAPI\line
+ if (options.error) \{\line
+ options.error(result);\line
+ \}\line
+ \}\line
+\line
+ options || (options = \{\});\line
+\line
+ switch (method) \{\line
+ case 'create':\line
+ requestContent['resource'] = model.toJSON();\line
+ return MyAPI.create(model, success, error);\line
+\line
+ case 'update':\line
+ requestContent['resource'] = model.toJSON();\line
+ return MyAPI.update(model, success, error);\line
+\line
+ case 'delete':\line
+ return MyAPI.destroy(model, success, error);\line
+\line
+ case 'read':\line
+ if (model.attributes[model.idAttribute]) \{\line
+ return MyAPI.find(model, success, error);\line
+ \} else \{\line
+ return MyAPI.findAll(model, success, error);\line
+ \}\line
+ \}\line
+\};\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This pattern delegates API calls to a new object, which could be a Backbone-style class that supports events. This can be safely tested separately, and potentially used with libraries other than Backbone.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 There are quite a few sync implementations out there:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Backbone localStorage\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Backbone offline\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Backbone Redis\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab backbone-parse\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab backbone-websql\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Backbone Caching Sync\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Conflict Management\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Like most client-side projects, Backbone.js wraps everything in an immediately-invoked function expression:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 (function()\{\line
+ // Backbone.js\line
+\}).call(this);\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Several things happen during this configuration stage. A Backbone \u8220"namespace\u8221" is created, and multiple versions of Backbone on the same page are supported through the noConflict mode:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 var root = this;\line
+var previousBackbone = root.Backbone;\line
+\line
+Backbone.noConflict = function() \{\line
+ root.Backbone = previousBackbone;\line
+ return this;\line
+\};\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Multiple versions of Backbone can be used on the same page by calling noConflict like this:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 var Backbone19 = Backbone.noConflict();\line
+// Backbone19 refers to the most recently loaded version,\line
+// and `window.Backbone` will be restored to the previously\line
+// loaded version\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 This initial configuration code also supports CommonJS modules so Backbone can be used in Node projects:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 var Backbone;\line
+if (typeof exports !== 'undefined') \{\line
+ Backbone = exports;\line
+\} else \{\line
+ Backbone = root.Backbone = \{\};\line
+\}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 The existence of Underscore.js (also by DocumentCloud) and a jQuery-like library is checked as well.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Leverage Events\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Backbone\u8217's classes are designed to be inherited from. Every single one of these classes inherits from Backbone.Events:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Backbone.Model\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Backbone.Collection\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Backbone.Router\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Backbone.History\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Backbone.View\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 That means when designing applications built with Backbone, events are a key architectural component. Events are the standard way to deal with user interface actions, through the declarative event bindings on views, and also model and collection changes. However, you can easily add your own custom events.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 When learning Backbone it\u8217's important to get a feel for the built-in event names. Incorrectly binding a collection reset event, for example, could cause your application to render more often than it should. Mastering events is one of the quickest ways to become more productive with Backbone.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Underscore.js\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Since Backbone depends on Underscore, it\u8217's worth keeping this in mind when dealing with any kind of arrays or collections of data. Also, familiarity with Underscore\u8217's methods will help work with Backbone.Collection effectively.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Views\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 It\u8217's easy to slip into using ,\u8198?{\i b}{\i u}{\i t}{\i a}{\i v}{\i o}{\i i}{\i d}{\i t}{\i h}{\i i}{\i s}{\i w}{\i h}{\i e}{\i r}{\i e}{\i p}{\i o}{\i s}{\i s}{\i i}{\i b}{\i l}{\i e}.\u8198?{\i B}{\i a}{\i c}{\i k}{\i b}{\i o}{\i n}{\i e}{\i c}{\i a}{\i c}{\i h}{\i e}{\i s}{\i a}{\i v}{\i i}{\i e}{\i w}\u8217'{\i s}{\i e}{\i l}{\i e}{\i m}{\i e}{\i n}{\i t},\u8198?{\i s}{\i o}{\i u}{\i s}{\i e}{\i t}{\i h}{\i i}{\i s}.\u8198?el instead. Design views based on the single responsibility principle.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 It might be tempting to let \u8220"container\u8221" view render HTML directly by using $().html, but resisting the temptation and creating a hierarchy of views will make it much easier to debug your code and write automated tests.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Interestingly, Backbone doesn\u8217't have a lot of code dedicated to templates, but it can work with the template method. I use this with RequireJS text file dependencies to load remote templates during development, then I use the RequireJS build script to generate something suitable for deployment. This makes code easy to test and fast to load.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 API Style\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Backbone\u8217's API is thankfully very consistent. Even the history API accepts a silent option, which is used throughout the library to stop events from firing when they\u8217're not required.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Backbone\u8217's collections have Underscore\u8217's chainable API, which can be handy, but care must be taken to use this correctly.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Testing Backbone\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 So far we\u8217've been reviewing Backbone\u8217's code to demystify the framework as a whole. However, it\u8217's worth noting that other technologies work very well with Backbone and Underscore. RequireJS and AMD modules can be a great way to break up projects.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 However, one area that Backbone doesn\u8217't address is testing. This is unfortunate, because testing Backbone projects definitely isn\u8217't obvious. Later in the book we\u8217'll look at testing in more detail.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Namespacing\par}
{\pard \ql \f0 \sa180 \li0 \fi0 When learning how to use Backbone, an important and commonly overlooked area by tutorials is namespacing. If you already have experience with namespacing in JavaScript, the following section will provide some advice on how to specifically apply concepts you know to Backbone, however I will also be covering explanations for beginners to ensure everyone is on the same page.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 What is namespacing?\par}
@@ -1290,9 +1454,34 @@ MongoDB
sudo chown `id -u` /data/db\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Running and connecting to your server}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Once this is done, open up two terminal windows.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 In the first, {\f1 cd} to your MongoDB bin directory or type in the complete path to it. You\u8217'll need to start mongod`.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 In the first, {\f1 cd} to your MongoDB bin directory or type in the complete path to it. You\u8217'll need to start {\f1 mongod}.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 $ ./bin/mongod\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Next, in the second terminal, start the `mongoBuilding Backbone.js Apps With Ruby, Sinatra, MongoDB and Haml\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Next, in the second terminal, start the {\f1 mongo} shell which will connect up to localhost by default.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 $ ./bin/mongo\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 That\u8217's it!.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Express and Mongoose\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Option 1 (HTML) and Option 2 (Jade) of the practical download both come with an install.sh bash script. This allows you to easily install Express, Mongoose, Jade (and optionally MongoDB if you prefer to) through npm (the node package manager).\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Make sure you have Node.js installed. If not, you can grab it {\field{\*\fldinst{HYPERLINK "http://nodejs.org/#download"}}{\fldrslt{\ul
+here
+}}}
+\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Next run {\f1 $ ./install.sh} at the terminal to install the rest of our dependencies. To see the exact contents of the install.sh file, see below:\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\b install.sh}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 #!/bin/bash\line
+npm install express\line
+npm install mongodb --mongodb:native\line
+npm install mongoose\line
+npm install jade\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab After you\u8217've installed all of the dependencies for the stack, we can get to cloning the repo containing our practicals and running them. Start by running the below lines:\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \f1 git clone git://github.com/addyosmani/backbone-boilerplates.git\line
+cd option2\line
+node app.js\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 For option1 (without Jade), simply cd into option1 and run {\f1 node app.js} from there.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Finally, either of the example apps can now be accessed by navigating to:\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Option 1: {\f1 http://localhost:3000/static.html}\par}
+{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab Option 2: {\f1 http://localhost:3000/todo}\sa180\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 That\u8217's it! Whilst there\u8217's a lot more than can be done to expand on the concepts covered so far, the base we\u8217're reviewed should be enough to get you up and running with this stack if you wish to use it with Backbone.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Building Backbone.js Apps With Ruby, Sinatra, MongoDB and Haml\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Introduction\par}
{\pard \ql \f0 \sa180 \li0 \fi0 In this chapter we\u8217're going to explore writing Backbone.js applications with a Ruby back-end. To assist with this, we\u8217're going to use {\field{\*\fldinst{HYPERLINK "http://www.sinatrarb.com/"}}{\fldrslt{\ul
Sinatra
@@ -1483,13 +1672,16 @@ Sinatra: The Book
also contains a brief tutorial on DataMapper for anyone interested in exploring it further.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Practical\par}
{\pard \ql \f0 \sa180 \li0 \fi0 We\u8217're going to use Sinatra in a similar manner to how we used Express in the last chapter. It will power a RESTful API supporting CRUD operations. Together with a MongoDB data store, this will allow us to easily persist data (todo items) whilst ensuring they are stored in a database. If you\u8217've read the previous chapter or have gone through any of the Todo examples covered so far, you will find this surprisingly straight-forward.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Remember that the default Todo example included with Backbone.js already persists data, although it does this via a localStorage adapter. Luckily there aren\u8217't a great deal of changes needed to switch over to using our Sinatra-based API. Let\u8217's briefly review the code that will be powering the CRUD operations for this sections practical, as we go course won\u8217't be starting off with a near-complete base for most of our real world applications.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Remember that the default Todo example included with Backbone.js already persists data, although it does this via a localStorage adapter. Luckily there aren\u8217't a great deal of changes needed to switch over to using our Sinatra-based API. Let\u8217's briefly review the code that will be powering the CRUD operations for this sections practical, as we won\u8217't be starting off with a near-complete base for most of our real world applications.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs28 Installing The Prerequisites\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Ruby\par}
{\pard \ql \f0 \sa180 \li0 \fi0 If using OSX or Linux, Ruby may be one of a number of open-source packages that come pre-installed and you can skip over to the next paragraph. In case you would like to check if check if you have Ruby installed, open up the terminal prompt and type:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\f1 $ ruby -v}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 The output of this will either be the version of Ruby installed or an error complaining that Ruby wasn\u8217't found.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Should you need to install Ruby manually (e.g for an operating system such as Windows), you can do so by downloading the latest version from http://www.ruby-lang.org/en/downloads/. Alternatively, (RVM)[http://beginrescueend.com/rvm/install/] (Ruby Version Manager) is a command-line tool that allows you to easily install and manage multiple ruby environments with ease.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 Should you need to install Ruby manually (e.g for an operating system such as Windows), you can do so by downloading the latest version from http://www.ruby-lang.org/en/downloads/. Alternatively, {\field{\*\fldinst{HYPERLINK "http://beginrescueend.com/rvm/install/"}}{\fldrslt{\ul
+RVM
+}}}
+ (Ruby Version Manager) is a command-line tool that allows you to easily install and manage multiple ruby environments with ease.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Ruby Gems\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Next, we will need to install Ruby Gems. Gems are a standard way to package programs or libraries written in Ruby and with Ruby Gems it\u8217's possible to install additional dependencies for Ruby applications very easily.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 On OSX, Linux or Windows go to {\field{\*\fldinst{HYPERLINK "http://rubyforge.org/projects/rubygems"}}{\fldrslt{\ul
@@ -1499,7 +1691,7 @@ http://rubyforge.org/projects/rubygems
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 $> tar xzvf rubygems.tgz\line
$> cd rubygems\line
$> sudo ruby setup.rb\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 There will likely be a version number included in your download and you should make sure to include this when tying the above. Finally, a symlink (symbolic link) to tie everything togther should be fun as follows:\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 There will likely be a version number included in your download and you should make sure to include this when tying the above. Finally, a symlink (symbolic link) to tie everything togther should be run as follows:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\f1 $ sudo ln -s /usr/bin/gem1.8.17 /usr/bin/gem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 To check that Ruby Gems has been correctly installed, type the following into your terminal:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 $ gem -v\par}
@@ -1507,7 +1699,7 @@ $> sudo ruby setup.rb\par}
{\pard \ql \f0 \sa180 \li0 \fi0 With Ruby Gems setup, we can now easily install Sinatra. For Linux or OSX type this in your terminal:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\f1 $ sudo gem install sinatra}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 and if you\u8217're on Windows, enter the following at a command prompt:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 {\f1 c:\\\\ > gem install sinatra}\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\f1 c:\\> gem install sinatra}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Haml\par}
{\pard \ql \f0 \sa180 \li0 \fi0 As with other DSLs and frameworks, Sinatra supports a wide range of different templating engines. {\field{\*\fldinst{HYPERLINK "http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html"}}{\fldrslt{\ul
ERB
@@ -2659,10 +2851,10 @@ development version
zipball
}}}
\par}
-{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab {\field{\*\fldinst{HYPERLINK ""}}{\fldrslt{\ul
+{\pard \ql \f0 \sa180 \li360 \fi-360 \bullet \tx360\tab {\field{\*\fldinst{HYPERLINK "http://github.com/addyosmani/backbone.paginator"}}{\fldrslt{\ul
Repository
}}}
-http://github.com/addyosmani/backbone.paginator)\sa180\par}
+\sa180\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Live Examples\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Live previews of both pagination components using the Netflix API can be found below. Download the tarball or fork the repository to experiment with these examples further.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Demo 1: {\field{\*\fldinst{HYPERLINK "http://addyosmani.github.com/backbone.paginator/examples/netflix-request-paging/index.html"}}{\fldrslt{\ul
@@ -2787,7 +2979,7 @@ Infinite Pagination (Backbone.Paginator.requestPager())
{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\b Collection.requestPreviousPage()} - go to the previous page\par}
{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\b Collection.howManyPer(n)} - set the number of items to display per page\sa180\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Paginator.clientPager\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 The {\f1 clientPager} works similar to the {\f1 requestPager}, except that our configuration values influence the pagination of data already returned at a UI-level. Whilst not shown (yet) there is also a lot more UI logic that ties in with the {\f1 clientPager}. An example of this can be seen in \u226?\u8364?\u732?views/clientPagination.js.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 The {\f1 clientPager} works similar to the {\f1 requestPager}, except that our configuration values influence the pagination of data already returned at a UI-level. Whilst not shown (yet) there is also a lot more UI logic that ties in with the {\f1 clientPager}. An example of this can be seen in views/clientPagination.js.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 1. Create a new paginated collection with a model and URL\par}
{\pard \ql \f0 \sa180 \li0 \fi0 As with {\f1 requestPager}, let\u8217's first create a new Paginated {\f1 Backbone.Paginator.clientPager} collection, with a model and base URL:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 var PaginatedCollection = Backbone.Paginator.clientPager.extend(\{\line
@@ -3010,7 +3202,7 @@ Backbone fundamentals
{\pard \ql \f0 \sa180 \li0 \fi0 For this application, I opted for the nested namespacing pattern. Implemented correctly, this enables you to clearly identify if items being referenced in your app are views, other modules and so on. This initial structure is a sane place to also include application defaults (unless you prefer maintaining those in a separate file).\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 window.mobileSearch = window.mobileSearch || \{\line
views: \{\line
- appview: new AppView\line
+ appview: new AppView()\line
\},\line
routers:\{\line
workspace:new Workspace()\line
@@ -3061,7 +3253,7 @@ BDD
Dan North
}}}
(the authority on BDD) which attempts to test the behavior of software. It\u8217's considered second-generation as it came out of merging ideas from Domain driven design (DDD) and lean software development, helping teams to deliver high quality software by answering many of the more confusing questions early on in the agile process. Such questions commonly include those concerning documentation and testing.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 If you were to read a book on BDD, it\u8217's likely to also be described as being \u8216'outside-in and pull-based\u8217'. The reason for this is that it borrows the idea of of pulling features from Lean manufacturing which effectively ensures that the right software solutions are being written by a) focusing on expected outputs of the system and b) ensuring these outputs are achieved.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 If you were to read a book on BDD, it\u8217's likely to also be described as being \u8216'outside-in and pull-based\u8217'. The reason for this is that it borrows the idea of pulling features from Lean manufacturing which effectively ensures that the right software solutions are being written by a) focusing on expected outputs of the system and b) ensuring these outputs are achieved.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 BDD recognizes that there are usually multiple stakeholders in a project and not a single amorphous user of the system. These different groups will be affected by the software being written in differing ways and will have a varying opinion of what quality in the system means to them. It\u8217's for this reason that it\u8217's important to understand who the software will be bringing value you and exactly what in it will be valuable to them.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Finally, BDD relies on automation. Once you\u8217've defined the quality expected, your team will likely want to check on the functionality of the solution being built regularly and compare it to the results they expect. In order to facilitate this efficiently, the process has to be automated. BDD relies heavily on the automation of specification-testing and Jasmine is a tool which can assist with this.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 BDD helps both developers and non-technical stakeholders:\par}
@@ -3545,7 +3737,7 @@ expect('click').toHaveBeenTriggeredOn($('#el'));\par}
</div>\line
</div>\par}
{\pard \ql \f0 \sa180 \li0 \fi0 The second spec fails with the following message:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Expected \u8217'\u8217' to contain {\f1 '<label class="todo-content">My Todo</label>'}.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\f1 Expected '' to contain '<label class="todo-content">My Todo</label>'.}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 The reason for this is the default behavior for render() doesn\u8217't create any markup. Let\u8217's write a replacement for render() which fixes this:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 render: function() \{\line
var template = '<label class="todo-content"><%= text %></label>';\line
@@ -3611,7 +3803,7 @@ expect('click').toHaveBeenTriggeredOn($('#el'));\par}
\line
\});\par}
{\pard \ql \f0 \sa180 \li0 \fi0 This will fail with the following message:\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Expected \u8216'My Todo\u8217' to have class \u8216'done\u8217'.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 {\f1 Expected '<label class="todo-content">My Todo</label>' to have class 'done'.}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 which can be fixed in the existing render() method as follows:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 render: function() \{\line
var template = '<label class="todo-content">' +\line
@@ -3687,7 +3879,7 @@ SinonJS
}}}
as well as how to test Backbone routers, do consider reading his series.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Exercise\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 As an exercise, I recommend now trying the Jasmine Koans in {\f1 practicals\\jasmine-joans} and trying to fix some of the purposefully failing tests it has to offer. This is an excellent way of not just learning how Jasmine specs and suites work, but working through the examples (without peaking back) will also put your Backbone skills to test too.\par}
+{\pard \ql \f0 \sa180 \li0 \fi0 As an exercise, I recommend now trying the Jasmine Koans in {\f1 practicals\\jasmine-joans} and trying to fix some of the purposefully failing tests it has to offer. This is an excellent way of not just learning how Jasmine specs and suites work, but working through the examples (without peeking back) will also put your Backbone skills to test too.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs32 Further reading\par}
{\pard \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab {\field{\*\fldinst{HYPERLINK "http://japhr.blogspot.com/2011/11/jasmine-backbonejs-revisited.html"}}{\fldrslt{\ul
Jasmine + Backbone Revisited
View
278 index.html
@@ -33,7 +33,7 @@
</p>
<div style="width:500px">
-<iframe src="http://ghbtns.com/github-btn.html?user=addyosmani&amp;repo=backbone-fundamentals&amp;type=watch&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
+<iframe src="http://markdotto.github.com/github-buttons/github-btn.html?user=addyosmani&amp;repo=backbone-fundamentals&amp;type=watch&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
<iframe allowtransparency="true" frameborder="0" scrolling="no" src="http://platform.twitter.com/widgets/tweet_button.1333103182.html#_=1333404284780&amp;count=horizontal&amp;id=twitter-widget-0&amp;lang=en&amp;original_referer=http%3A%2F%2Faddyosmani.github.com%2Fbackbone-fundamentals%2F&amp;size=m&amp;text=Developing%20Backbone.js%20Applications&amp;url=https%3A%2F%2Fgithub.com%2Faddyosmani%2Fbackbone-fundamentals&amp;via=addy_osmani" class="twitter-share-button twitter-count-horizontal" style="width: 107px; height: 20px; " title="Twitter Tweet Button"></iframe>
<script id="twitter-wjs" src="//platform.twitter.com/widgets.js"></script><script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
@@ -323,7 +323,7 @@ <h3 id="models-views-presenters">Models, Views &amp; Presenters</h3>
<p>The most common implementation of MVP is one which uses a Passive View (a view which is for all intents and purposes &quot;dumb&quot;), containing little to no logic. MVP models are almost identical to MVC models and handle application data. The presenter acts as a mediator which talks to both the view and model, however both of these are isolated from each other. They effectively bind models to views, a responsibility held by Controllers in MVC. Presenters are at the heart of the MVP pattern and as you can guess, incorporate the presentation logic behind views.</p>
<p>Solicited by a view, presenters perform any work to do with user requests and pass data back to them. In this respect, they retrieve data, manipulate it and determine how the data should be displayed in the view. In some implementations, the presenter also interacts with a service layer to persist data (models). Models may trigger events but it's the presenter's role to subscribe to them so that it can update the view. In this passive architecture, we have no concept of direct data binding. Views expose setters which presenters can use to set data.</p>
<p>The benefit of this change from MVC is that it increases the testability of your application and provides a more clean separation between the view and the model. This isn't however without its costs as the lack of data binding support in the pattern can often mean having to take care of this task separately.</p>
-<p>Although a common implementation of a <a href="http://martinfowler.com/eaaDev/PassiveScreen.html">Passive View</a> is for the view to implement an interface, there are variations on it, including the use of events which can decouple the View from the Presenter a little more. As we don't have the interface construct in JavaScript, we're using it more as more a protocol than an explicit interface here. It's technically still an API and it's probably fair for us to refer to it as an interface from that perspective.</p>
+<p>Although a common implementation of a <a href="http://martinfowler.com/eaaDev/PassiveScreen.html">Passive View</a> is for the view to implement an interface, there are variations on it, including the use of events which can decouple the View from the Presenter a little more. As we don't have the interface construct in JavaScript, we're using it more and more a protocol than an explicit interface here. It's technically still an API and it's probably fair for us to refer to it as an interface from that perspective.</p>
<p>There is also a <a href="http://martinfowler.com/eaaDev/SupervisingPresenter.html">Supervising Controller</a> variation of MVP, which is closer to the MVC and <a href="http://en.wikipedia.org/wiki/Model_View_ViewModel">MVVM</a> patterns as it provides data-binding from the Model directly from the View. Key-value observing (KVO) plugins (such as Derick Bailey's Backbone.ModelBinding plugin) introduce this idea of a Supervising Controller to Backbone.</p>
<h2 id="mvp-or-mvc">MVP or MVC?</h2>
<p>MVP is generally used most often in enterprise-level applications where it's necessary to reuse as much presentation logic as possible. Applications with very complex views and a great deal of user interaction may find that MVC doesn't quite fit the bill here as solving this problem may mean heavily relying on multiple controllers. In MVP, all of this complex logic can be encapsulated in a presenter, which can simplify maintenance greatly.</p>
@@ -409,6 +409,11 @@ <h3 id="why-should-you-consider-using-it">Why should you consider using it?</h3>
<li>Model data, views and routers in a succinct manner</li>
<li>Provide DOM, model and collection synchronization</li>
</ul>
+<h2 id="is-backbone-right-for-you">Is Backbone right for you?</h2>
+<p>Does the following describe you?:</p>
+<p>&quot;I want something flexible which offers a minimalist solution to separating concerns in my application. It should support a persistence layer and RESTful sync, models, views (with controllers), event-driven communication, templating and routing. It should be imperative, allowing one to update the View when a model changes. I’d like some decisions about the architecture left up to me. Ideally, many large companies have used the solution to build non-trivial applications.</p>
+<p>As I may be building something complex, I’d like there to be an active extension community around the framework that have already tried addressing larger problems (Marionette, Chaplin, Aura, Thorax). Ideally, there are also scaffolding tools (grunt-bbb, brunch) available for the solution.&quot;</p>
+<p>If so, continue reading.</p>
<h2 id="the-basics-1">The Basics</h2>
<p>In this section, you'll learn the essentials of Backbone's models, views, collections and routers, as well as about using namespacing to organize your code. This isn't meant as a replacement for the official documentation, but it will help you understand many of the core concepts behind Backbone before you start building applications with it.</p>
<ul>
@@ -560,7 +565,7 @@ <h4 id="model.set">Model.set()</h4>
<span class="kw">var</span> myPhoto = <span class="kw">new</span> Photo();
<span class="kw">myPhoto</span>.<span class="fu">set</span>({ <span class="dt">title</span>: <span class="st">&quot;On the beach&quot;</span> });
<span class="co">//logs Remember to set a source for your image!</span></code></pre>
-<p><strong>Note</strong>: Backbone passes the <code>attributes</code> object by shallow copy to the <code>validate</code> function using the Underscore <code>_.extend</code> method. This means that it is not possible to change any <code>Number</code>, <code>String</code> or <code>Boolean</code> attribute by reference in the way that one might expect a JavaScript object to behave. As shallow copy doesn't copy objects by implicitly copying them, but rather, by reference, one can change the attributes on those objects.</p>
+<p><strong>Note</strong>: Backbone passes the <code>attributes</code> object by shallow copy to the <code>validate</code> function using the Underscore <code>_.extend</code> method. This means that it is not possible to change any <code>Number</code>, <code>String</code> or <code>Boolean</code> attribute by reference in the way that one might expect a JavaScript object to behave. As shallow copy doesn't copy objects by implicitly copying them, but rather, by reference, one ca change the attributes on those objects.</p>
<p>An example of this (by @fivetanley) is available <a href="http://jsfiddle.net/2NdDY/7/">here</a>.</p>
<h3 id="views-1"><a name="thebasics-views" id="thebasics-views">Views</a></h3>
<p>Views in Backbone don't contain the markup for your application, but rather they are there to support models by defining the logic for how they should be represented to the user. This is usually achieved using JavaScript templating (e.g. Mustache, jQuery-tmpl, etc.). A view's <code>render()</code> function can be bound to a model's <code>change()</code> event, allowing the view to always be up to date without requiring a full page refresh.</p>
@@ -646,14 +651,29 @@ <h3 id="collections"><a name="thebasics-collections" id="thebasics-collections">
<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> PhotoCollection = <span class="kw">new</span> <span class="kw">Backbone</span>.<span class="fu">Collection</span>;
<span class="kw">PhotoCollection</span>.<span class="fu">url</span> = <span class="ch">&#39;/photos&#39;</span>;
<span class="kw">PhotoCollection</span>.<span class="fu">fetch</span>();</code></pre>
-<p>Under the covers, <code>Backbone.sync</code> is the function called every time Backbone tries to read or save models to the server. It uses jQuery or Zepto's ajax implementations to make these RESTful requests, however this can be overridden as per your needs.</p>
+<p>During configuration, Backbone sets a variable to denote if extended HTTP methods are supported by the server. Another setting controls if the server understands the correct MIME type for JSON:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">Backbone</span>.<span class="fu">emulateHTTP</span> = <span class="kw">false</span>;
+<span class="kw">Backbone</span>.<span class="fu">emulateJSON</span> = <span class="kw">false</span>;</code></pre>
+<p>The Backbone.sync method that uses these values is actually an integral part of Backbone.js. A jQuery-like ajax method is assumed, so HTTP parameters are organised based on jQuery’s API. Searching through the code for calls to the sync method show it’s used whenever a model is saved, fetched, or deleted (destroyed).</p>
+<p>Under the covers, <code>Backbone.sync</code> is the function called every time Backbone tries to read or save models to the server. It uses jQuery or Zepto's ajax implementations to make these RESTful requests, however this can be overridden as per your needs. :</p>
+<p>The sync function may be overriden globally as Backbone.sync, or at a finer-grained level, by adding a sync function to a Backbone collection or to an individual model.</p>
+<p>There’s no fancy plugin API for adding a persistence layer – simply override Backbone.sync with the same function signature:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">Backbone</span>.<span class="fu">sync</span> = <span class="kw">function</span>(method, model, options) {
+};</code></pre>
+<p>The default methodMap is useful for working out what the method argument does:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> methodMap = {
+ <span class="ch">&#39;create&#39;</span>: <span class="ch">&#39;POST&#39;</span>,
+ <span class="ch">&#39;update&#39;</span>: <span class="ch">&#39;PUT&#39;</span>,
+ <span class="ch">&#39;delete&#39;</span>: <span class="ch">&#39;DELETE&#39;</span>,
+ <span class="ch">&#39;read&#39;</span>: <span class="ch">&#39;GET&#39;</span>
+};</code></pre>
<p>In the above example if we wanted to log an event when <code>.sync()</code> was called, we could do this:</p>
<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">Backbone</span>.<span class="fu">sync</span> = <span class="kw">function</span>(method, model) {
<span class="kw">console</span>.<span class="fu">log</span>(<span class="st">&quot;I&#39;ve been passed &quot;</span> + method + <span class="st">&quot; with &quot;</span> + <span class="kw">JSON</span>.<span class="fu">stringify</span>(model));
};</code></pre>
<p><strong>Resetting/Refreshing Collections</strong></p>
<p>Rather than adding or removing models individually, you might occasionally wish to update an entire collection at once. <code>Collection.reset()</code> allows us to replace an entire collection with new models as follows:</p>
-<p><code>javascript PhotoCollection.reset([ {title: &quot;My trip to Scotland&quot;, src: &quot;scotland-trip.jpg&quot;}, {title: &quot;The flight from Scotland&quot;, src: &quot;long-flight.jpg&quot;}, {title: &quot;Latest snap of lock-ness&quot;, src: &quot;lockness.jpg&quot;}]);</code> Note that using <code>Collection.reset()</code> doesn't fire any <code>add</code> or <code>remove</code> events. A <code>reset</code> event is fired instead.</p>
+<p><code>javascript PhotoCollection.reset([ {title: &quot;My trip to Scotland&quot;, src: &quot;scotland-trip.jpg&quot;}, {title: &quot;The flight from Scotland&quot;, src: &quot;long-flight.jpg&quot;}, {title: &quot;Latest snap of Loch Ness&quot;, src: &quot;lochness.jpg&quot;}]);</code> Note that using <code>Collection.reset()</code> doesn't fire any <code>add</code> or <code>remove</code> events. A <code>reset</code> event is fired instead.</p>
<h3 id="underscore-utility-functions">Underscore utility functions</h3>
<p>As Backbone requires Underscore as a hard dependency, we're able to use many of the utilities it has to offer to aid with our application development. Here's an example of how Underscore's <code>sortBy()</code> method can be used to sort a collection of photos based on a particular attribute.</p>
<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> sortedByAlphabet = <span class="kw">PhotoCollection</span>.<span class="fu">sortBy</span>(<span class="kw">function</span> (photo) {
@@ -749,6 +769,158 @@ <h4 id="backbone.history">Backbone.history</h4>
<span class="kw">this</span>.<span class="fu">zoom</span>(factor); <span class="co">//imagine this zooms into the image</span>
<span class="kw">this</span>.<span class="fu">navigate</span>(<span class="st">&quot;zoom/&quot;</span> + factor, <span class="kw">true</span>); <span class="co">//updates the fragment for us and triggers the route</span>
}</code></pre>
+<h3 id="chainable-api">Chainable API</h3>
+<p>Another bit of sugar is the support for Underscore’s chain method. This works by calling the original method with the current array of models and returning the result. In case you haven’t seen it before, the chainable API looks like this:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> collection = <span class="kw">new</span> <span class="kw">Backbone</span>.<span class="fu">Collection</span>([
+ { <span class="dt">name</span>: <span class="ch">&#39;Tim&#39;</span>, <span class="dt">age</span>: <span class="dv">5</span> },
+ { <span class="dt">name</span>: <span class="ch">&#39;Ida&#39;</span>, <span class="dt">age</span>: <span class="dv">26</span> },
+ { <span class="dt">name</span>: <span class="ch">&#39;Rob&#39;</span>, <span class="dt">age</span>: <span class="dv">55</span> }
+]);
+
+<span class="kw">collection</span>.<span class="fu">chain</span>()
+ .<span class="fu">filter</span>(<span class="kw">function</span>(item) { <span class="kw">return</span> <span class="kw">item</span>.<span class="fu">get</span>(<span class="ch">&#39;age&#39;</span>) &gt; <span class="dv">10</span>; })
+ .<span class="fu">map</span>(<span class="kw">function</span>(item) { <span class="kw">return</span> <span class="kw">item</span>.<span class="fu">get</span>(<span class="ch">&#39;name&#39;</span>); })
+ .<span class="fu">value</span>();
+
+<span class="co">// Will return [&#39;Ida&#39;, &#39;Rob&#39;]</span>
+Some of the Backbone-specific method will <span class="kw">return</span> <span class="kw">this</span>, which means they can be chained as <span class="dt">well</span>:
+
+<span class="kw">var</span> collection = <span class="kw">new</span> <span class="kw">Backbone</span>.<span class="fu">Collection</span>();
+
+collection
+ .<span class="fu">add</span>({ <span class="dt">name</span>: <span class="ch">&#39;John&#39;</span>, <span class="dt">age</span>: <span class="dv">23</span> })
+ .<span class="fu">add</span>({ <span class="dt">name</span>: <span class="ch">&#39;Harry&#39;</span>, <span class="dt">age</span>: <span class="dv">33</span> })
+ .<span class="fu">add</span>({ <span class="dt">name</span>: <span class="ch">&#39;Steve&#39;</span>, <span class="dt">age</span>: <span class="dv">41</span> });
+
+<span class="kw">collection</span>.<span class="fu">pluck</span>(<span class="ch">&#39;name&#39;</span>);
+<span class="co">// [&#39;John&#39;, &#39;Harry&#39;, &#39;Steve&#39;]</span></code></pre>
+<h3 id="backbones-inheritance-implementation">Backbone’s inheritance Implementation</h3>
+<p>The comments indicate that the inherits function is inspired by goog.inherits. Google’s implementation is from the Closure Library, but Backbone’s API accepts two objects (incorrectly referred to as a hash) containing “instance” and “static” methods. Each of Backbone’s objects has an extend method:</p>
+<p>Model.extend = Collection.extend = Router.extend = View.extend = extend; Most development with Backbone is based around inheriting from these objects, and they’re designed to mimic a classical object-oriented implementation.</p>
+<p>Backbone uses Underscore’s extend method:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript">each(<span class="kw">slice</span>.<span class="fu">call</span>(arguments, <span class="dv">1</span>), <span class="kw">function</span>(source) {
+ <span class="kw">for</span> (<span class="kw">var</span> prop <span class="kw">in</span> source) {
+ obj[prop] = source[prop];
+ }
+});
+
+<span class="kw">return</span> obj;</code></pre>
+<p>This isn’t the same as ES5’s Object.create, it’s actually copying properties (methods and values) from one object to another. Since this isn’t enough to support Backbone’s inheritance and class model, the following steps are performed:</p>
+<ul>
+<li><p>The instance methods are checked to see if there’s a constructor property. If so, the class’s constructor is used, otherwise the parent’s constructor is used (i.e., Backbone.Model)</p></li>
+<li><p>Underscore’s extend method is called to add the parent class’s methods to the new child class The prototype property of a blank constructor function is assigned with the parent’s prototype, and a new instance of this is set to the child’s prototype property</p></li>
+<li><p>Underscore’s extend method is called twice to add the static and instance methods to the child class</p></li>
+<li><p>The child’s prototype’s constructor and a <strong>super</strong> property are assigned</p></li>
+</ul>
+<p>This pattern is also used for classes in CoffeeScript, so Backbone classes are compatible with CoffeeScript classes.</p>
+<h3 id="backbones-sync-api">Backbone’s Sync API</h3>
+<p>The Backbone.sync method is intended to be overridden to support other backends. The built-in method is tailed to a certain breed of RESTful JSON APIs – Backbone was originally extracted from a Ruby on Rails application, which uses HTTP methods like PUT the same way.</p>
+<p>The way this works is the model and collection classes have a sync method that calls Backbone.sync. Both will call this.sync internally when fetching, saving, or deleting items.</p>
+<p>The sync method is called with three parameters:</p>
+<ul>
+<li>method: One of create, update, delete, read</li>
+<li>model: The Backbone model object</li>
+<li>options: May include success and error methods</li>
+</ul>
+<p>Implementing a new sync method can use the following pattern:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">Backbone</span>.<span class="fu">sync</span> = <span class="kw">function</span>(method, model, options) {
+ <span class="kw">var</span> requestContent = {}, success, error;
+
+ <span class="kw">function</span> success(result) {
+ <span class="co">// Handle results from MyAPI</span>
+ <span class="kw">if</span> (<span class="kw">options</span>.<span class="fu">success</span>) {
+ <span class="kw">options</span>.<span class="fu">success</span>(result);
+ }
+ }
+
+ <span class="kw">function</span> error(result) {
+ <span class="co">// Handle results from MyAPI</span>
+ <span class="kw">if</span> (<span class="kw">options</span>.<span class="fu">error</span>) {
+ <span class="kw">options</span>.<span class="fu">error</span>(result);
+ }
+ }
+
+ options || (options = {});
+
+ <span class="kw">switch</span> (method) {
+ <span class="kw">case</span> <span class="ch">&#39;create&#39;</span>:
+ requestContent[<span class="ch">&#39;resource&#39;</span>] = <span class="kw">model</span>.<span class="fu">toJSON</span>();
+ <span class="kw">return</span> <span class="kw">MyAPI</span>.<span class="fu">create</span>(model, success, error);
+
+ <span class="kw">case</span> <span class="ch">&#39;update&#39;</span>:
+ requestContent[<span class="ch">&#39;resource&#39;</span>] = <span class="kw">model</span>.<span class="fu">toJSON</span>();
+ <span class="kw">return</span> <span class="kw">MyAPI</span>.<span class="fu">update</span>(model, success, error);
+
+ <span class="kw">case</span> <span class="ch">&#39;delete&#39;</span>:
+ <span class="kw">return</span> <span class="kw">MyAPI</span>.<span class="fu">destroy</span>(model, success, error);
+
+ <span class="kw">case</span> <span class="ch">&#39;read&#39;</span>:
+ <span class="kw">if</span> (<span class="kw">model</span>.<span class="fu">attributes</span>[<span class="kw">model</span>.<span class="fu">idAttribute</span>]) {
+ <span class="kw">return</span> <span class="kw">MyAPI</span>.<span class="fu">find</span>(model, success, error);
+ } <span class="kw">else</span> {
+ <span class="kw">return</span> <span class="kw">MyAPI</span>.<span class="fu">findAll</span>(model, success, error);
+ }
+ }
+};</code></pre>
+<p>This pattern delegates API calls to a new object, which could be a Backbone-style class that supports events. This can be safely tested separately, and potentially used with libraries other than Backbone.</p>
+<p>There are quite a few sync implementations out there:</p>
+<ul>
+<li>Backbone localStorage</li>
+<li>Backbone offline</li>
+<li>Backbone Redis</li>
+<li>backbone-parse</li>
+<li>backbone-websql</li>
+<li>Backbone Caching Sync</li>
+</ul>
+<h3 id="conflict-management">Conflict Management</h3>
+<p>Like most client-side projects, Backbone.js wraps everything in an immediately-invoked function expression:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript">(<span class="kw">function</span>(){
+ <span class="co">// Backbone.js</span>
+}).<span class="fu">call</span>(<span class="kw">this</span>);</code></pre>
+<p>Several things happen during this configuration stage. A Backbone “namespace” is created, and multiple versions of Backbone on the same page are supported through the noConflict mode:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> root = <span class="kw">this</span>;
+<span class="kw">var</span> previousBackbone = <span class="kw">root</span>.<span class="fu">Backbone</span>;
+
+<span class="kw">Backbone</span>.<span class="fu">noConflict</span> = <span class="kw">function</span>() {
+ <span class="kw">root</span>.<span class="fu">Backbone</span> = previousBackbone;
+ <span class="kw">return</span> <span class="kw">this</span>;
+};</code></pre>
+<p>Multiple versions of Backbone can be used on the same page by calling noConflict like this:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> Backbone19 = <span class="kw">Backbone</span>.<span class="fu">noConflict</span>();
+<span class="co">// Backbone19 refers to the most recently loaded version,</span>
+<span class="co">// and `window.Backbone` will be restored to the previously</span>
+<span class="co">// loaded version</span></code></pre>
+<p>This initial configuration code also supports CommonJS modules so Backbone can be used in Node projects:</p>
+<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> Backbone;
+<span class="kw">if</span> (<span class="kw">typeof</span> exports !== <span class="ch">&#39;undefined&#39;</span>) {
+ Backbone = exports;
+} <span class="kw">else</span> {
+ Backbone = <span class="kw">root</span>.<span class="fu">Backbone</span> = {};
+}</code></pre>
+<p>The existence of Underscore.js (also by DocumentCloud) and a jQuery-like library is checked as well.</p>
+<h3 id="leverage-events">Leverage Events</h3>
+<p>Backbone’s classes are designed to be inherited from. Every single one of these classes inherits from Backbone.Events:</p>
+<ul>
+<li>Backbone.Model</li>
+<li>Backbone.Collection</li>
+<li>Backbone.Router</li>
+<li>Backbone.History</li>
+<li>Backbone.View</li>
+</ul>
+<p>That means when designing applications built with Backbone, events are a key architectural component. Events are the standard way to deal with user interface actions, through the declarative event bindings on views, and also model and collection changes. However, you can easily add your own custom events.</p>
+<p>When learning Backbone it’s important to get a feel for the built-in event names. Incorrectly binding a collection reset event, for example, could cause your application to render more often than it should. Mastering events is one of the quickest ways to become more productive with Backbone.</p>
+<h4 id="underscore.js">Underscore.js</h4>
+<p>Since Backbone depends on Underscore, it’s worth keeping this in mind when dealing with any kind of arrays or collections of data. Also, familiarity with Underscore’s methods will help work with Backbone.Collection effectively.</p>
+<h4 id="views-2">Views</h4>
+<p>It’s easy to slip into using <span class="math">, <em>b</em><em>u</em><em>t</em><em>a</em><em>v</em><em>o</em><em>i</em><em>d</em><em>t</em><em>h</em><em>i</em><em>s</em><em>w</em><em>h</em><em>e</em><em>r</em><em>e</em><em>p</em><em>o</em><em>s</em><em>s</em><em>i</em><em>b</em><em>l</em><em>e</em>. <em>B</em><em>a</em><em>c</em><em>k</em><em>b</em><em>o</em><em>n</em><em>e</em><em>c</em><em>a</em><em>c</em><em>h</em><em>e</em><em>s</em><em>a</em><em>v</em><em>i</em><em>e</em><em>w</em>’<em>s</em><em>e</em><em>l</em><em>e</em><em>m</em><em>e</em><em>n</em><em>t</em>, <em>s</em><em>o</em><em>u</em><em>s</em><em>e</em><em>t</em><em>h</em><em>i</em><em>s</em>. </span>el instead. Design views based on the single responsibility principle.</p>
+<p>It might be tempting to let “container” view render HTML directly by using $().html, but resisting the temptation and creating a hierarchy of views will make it much easier to debug your code and write automated tests.</p>
+<p>Interestingly, Backbone doesn’t have a lot of code dedicated to templates, but it can work with the template method. I use this with RequireJS text file dependencies to load remote templates during development, then I use the RequireJS build script to generate something suitable for deployment. This makes code easy to test and fast to load.</p>
+<h4 id="api-style">API Style</h4>
+<p>Backbone’s API is thankfully very consistent. Even the history API accepts a silent option, which is used throughout the library to stop events from firing when they’re not required.</p>
+<p>Backbone’s collections have Underscore’s chainable API, which can be handy, but care must be taken to use this correctly.</p>
+<h4 id="testing-backbone">Testing Backbone</h4>
+<p>So far we’ve been reviewing Backbone’s code to demystify the framework as a whole. However, it’s worth noting that other technologies work very well with Backbone and Underscore. RequireJS and AMD modules can be a great way to break up projects.</p>
+<p>However, one area that Backbone doesn’t address is testing. This is unfortunate, because testing Backbone projects definitely isn’t obvious. Later in the book we'll look at testing in more detail.</p>
<h3 id="namespacing"><a name="thebasics-namespacing" id="thebasics-namespacing">Namespacing</a></h3>
<p>When learning how to use Backbone, an important and commonly overlooked area by tutorials is namespacing. If you already have experience with namespacing in JavaScript, the following section will provide some advice on how to specifically apply concepts you know to Backbone, however I will also be covering explanations for beginners to ensure everyone is on the same page.</p>
<h4 id="what-is-namespacing">What is namespacing?</h4>
@@ -1148,53 +1320,37 @@ <h4 id="mongodb">MongoDB</h4>
sudo chown `id -u` /data/db</code></pre>
<p><strong>Running and connecting to your server</strong></p>
<p>Once this is done, open up two terminal windows.</p>
-<p>In the first, <code>cd</code> to your MongoDB bin directory or type in the complete path to it. You'll need to start <cpde>mongod`.</p>
+<p>In the first, <code>cd</code> to your MongoDB bin directory or type in the complete path to it. You'll need to start <code>mongod</code>.</p>
<pre class="sourceCode html"><code class="sourceCode html">$ ./bin/mongod</code></pre>
-<p>Next, in the second terminal, start the `mongo</code shell which will connect up to localhost by default.
-
-```html
-$ ./bin/mongo
-```
-
-That's it!.
-
-####Express and Mongoose
-
-Option 1 (HTML) and Option 2 (Jade) of the practical download both come with an install.sh bash script. This allows you to easily install Express, Mongoose, Jade (and optionally MongoDB if you prefer to) through npm (the node package manager).
-
-* Make sure you have Node.js installed. If not, you can grab it [here](http://nodejs.org/#download)
-* Next run `$ ./install.sh` at the terminal to install the rest of our dependencies. To see the exact contents of the install.sh file, see below:
-
-**install.sh**
-
-```html
-#!/bin/bash
+<p>Next, in the second terminal, start the <code>mongo</code> shell which will connect up to localhost by default.</p>
+<pre class="sourceCode html"><code class="sourceCode html">$ ./bin/mongo</code></pre>
+<p>That's it!.</p>
+<h4 id="express-and-mongoose">Express and Mongoose</h4>
+<p>Option 1 (HTML) and Option 2 (Jade) of the practical download both come with an install.sh bash script. This allows you to easily install Express, Mongoose, Jade (and optionally MongoDB if you prefer to) through npm (the node package manager).</p>
+<ul>
+<li>Make sure you have Node.js installed. If not, you can grab it <a href="http://nodejs.org/#download">here</a></li>
+<li>Next run <code>$ ./install.sh</code> at the terminal to install the rest of our dependencies. To see the exact contents of the install.sh file, see below:</li>
+</ul>
+<p><strong>install.sh</strong></p>
+<pre class="sourceCode html"><code class="sourceCode html">#!/bin/bash
npm install express
npm install mongodb --mongodb:native
npm install mongoose
-npm install jade
-```
-
-
-* After you've installed all of the dependencies for the stack, we can get to cloning the repo containing our practicals and running them. Start by running the below lines:
-
-```html
-git clone git://github.com/addyosmani/backbone-boilerplates.git
+npm install jade</code></pre>
+<ul>
+<li>After you've installed all of the dependencies for the stack, we can get to cloning the repo containing our practicals and running them. Start by running the below lines:</li>
+</ul>
+<pre class="sourceCode html"><code class="sourceCode html">git clone git://github.com/addyosmani/backbone-boilerplates.git
cd option2
-node app.js
-```
-
-For option1 (without Jade), simply cd into option1 and run `node app.js` from there.
-
-Finally, either of the example apps can now be accessed by navigating to:
-
-* Option 1: `http://localhost:3000/static.html`
-* Option 2: `http://localhost:3000/todo`
-
-That's it! Whilst there's a lot more than can be done to expand on the concepts covered so far, the base we're reviewed should be enough to get you up and running with this stack if you wish to use it with Backbone.
-
-
-#<a name="stack2">Building Backbone.js Apps With Ruby, Sinatra, MongoDB and Haml</a></p>
+node app.js</code></pre>
+<p>For option1 (without Jade), simply cd into option1 and run <code>node app.js</code> from there.</p>
+<p>Finally, either of the example apps can now be accessed by navigating to:</p>
+<ul>
+<li>Option 1: <code>http://localhost:3000/static.html</code></li>
+<li>Option 2: <code>http://localhost:3000/todo</code></li>
+</ul>
+<p>That's it! Whilst there's a lot more than can be done to expand on the concepts covered so far, the base we're reviewed should be enough to get you up and running with this stack if you wish to use it with Backbone.</p>
+<h1 id="building-backbone.js-apps-with-ruby-sinatra-mongodb-and-haml"><a name="stack2">Building Backbone.js Apps With Ruby, Sinatra, MongoDB and Haml</a></h1>
<h2 id="introduction-1">Introduction</h2>
<p>In this chapter we're going to explore writing Backbone.js applications with a Ruby back-end. To assist with this, we're going to use <a href="http://www.sinatrarb.com/">Sinatra</a> - a DSL (domain specific language) for rapidly creating web applications in Ruby. Similar to the <a href="https://github.com/addyosmani/backbone-fundamentals/#stack1">section</a> on writing an application with Node.js, our server-side language (Ruby) will be used to power an API whilst Backbone.js will be the client consuming it.</p>
<h2 id="what-is-sinatra">What Is Sinatra?</h2>
@@ -1360,20 +1516,20 @@ <h2 id="getting-started">Getting started</h2>
<p>Note: Whilst we opted for the MongoDB Ruby Driver for this stack, you may also be interested in <strong>DataMapper</strong> - a solution which allows us to use the same API to talk to a number of different datastores. This works well for both relational and non-relational databases and more information is available on the official <a href="http://datamapper.org/why.html">project page</a>. <a href="http://sinatra-book.gittr.com/#datamapper">Sinatra: The Book</a> also contains a brief tutorial on DataMapper for anyone interested in exploring it further.</p>
<h1 id="practical-1">Practical</h1>
<p>We're going to use Sinatra in a similar manner to how we used Express in the last chapter. It will power a RESTful API supporting CRUD operations. Together with a MongoDB data store, this will allow us to easily persist data (todo items) whilst ensuring they are stored in a database. If you've read the previous chapter or have gone through any of the Todo examples covered so far, you will find this surprisingly straight-forward.</p>
-<p>Remember that the default Todo example included with Backbone.js already persists data, although it does this via a localStorage adapter. Luckily there aren't a great deal of changes needed to switch over to using our Sinatra-based API. Let's briefly review the code that will be powering the CRUD operations for this sections practical, as we go course won't be starting off with a near-complete base for most of our real world applications.</p>
+<p>Remember that the default Todo example included with Backbone.js already persists data, although it does this via a localStorage adapter. Luckily there aren't a great deal of changes needed to switch over to using our Sinatra-based API. Let's briefly review the code that will be powering the CRUD operations for this sections practical, as we won't be starting off with a near-complete base for most of our real world applications.</p>
<h3 id="installing-the-prerequisites"><a id="preq">Installing The Prerequisites</a></h3>
<h4 id="ruby">Ruby</h4>
<p>If using OSX or Linux, Ruby may be one of a number of open-source packages that come pre-installed and you can skip over to the next paragraph. In case you would like to check if check if you have Ruby installed, open up the terminal prompt and type:</p>
<p><code>$ ruby -v</code></p>
<p>The output of this will either be the version of Ruby installed or an error complaining that Ruby wasn't found.</p>
-<p>Should you need to install Ruby manually (e.g for an operating system such as Windows), you can do so by downloading the latest version from http://www.ruby-lang.org/en/downloads/. Alternatively, (RVM)[http://beginrescueend.com/rvm/install/] (Ruby Version Manager) is a command-line tool that allows you to easily install and manage multiple ruby environments with ease.</p>
+<p>Should you need to install Ruby manually (e.g for an operating system such as Windows), you can do so by downloading the latest version from http://www.ruby-lang.org/en/downloads/. Alternatively, <a href="http://beginrescueend.com/rvm/install/">RVM</a> (Ruby Version Manager) is a command-line tool that allows you to easily install and manage multiple ruby environments with ease.</p>
<h4 id="ruby-gems">Ruby Gems</h4>
<p>Next, we will need to install Ruby Gems. Gems are a standard way to package programs or libraries written in Ruby and with Ruby Gems it's possible to install additional dependencies for Ruby applications very easily.</p>
<p>On OSX, Linux or Windows go to <a href="http://rubyforge.org/projects/rubygems">http://rubyforge.org/projects/rubygems</a> and download the latest version of Ruby Gems. Once downloaded, open up a terminal, navigate to the folder where this resides and enter:</p>
<pre><code>$&gt; tar xzvf rubygems.tgz
$&gt; cd rubygems
$&gt; sudo ruby setup.rb</code></pre>
-<p>There will likely be a version number included in your download and you should make sure to include this when tying the above. Finally, a symlink (symbolic link) to tie everything togther should be fun as follows:</p>
+<p>There will likely be a version number included in your download and you should make sure to include this when tying the above. Finally, a symlink (symbolic link) to tie everything togther should be run as follows:</p>
<p><code>$ sudo ln -s /usr/bin/gem1.8.17 /usr/bin/gem</code></p>
<p>To check that Ruby Gems has been correctly installed, type the following into your terminal:</p>
<pre><code>$ gem -v</code></pre>
@@ -1381,7 +1537,7 @@ <h4 id="sinatra">Sinatra</h4>
<p>With Ruby Gems setup, we can now easily install Sinatra. For Linux or OSX type this in your terminal:</p>
<p><code>$ sudo gem install sinatra</code></p>
<p>and if you're on Windows, enter the following at a command prompt:</p>
-<p><code>c:\\ &gt; gem install sinatra</code></p>
+<p><code>c:\&gt; gem install sinatra</code></p>
<h4 id="haml-1">Haml</h4>
<p>As with other DSLs and frameworks, Sinatra supports a wide range of different templating engines. <a href="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html">ERB</a> is the one most often recommended by the Sinatra camp, however as a part of this chapter, we're going to explore the use of <a href="http://haml.hamptoncatlin.com/">Haml</a> to define our application templates.</p>
<p>Haml stands for HTML Abstractional Markup Language and is a lightweight markup language abstraction that can be used to describe HTML without the need to use traditional markup language semantics (such as opening and closing tags).</p>
@@ -1441,7 +1597,7 @@ <h3 id="application-files">Application Files</h3>
<p>Lastly, the <code>views</code> directory hosts the Haml source files for our application's index and templates, both of which are compiled to standard HTML markup at runtime.</p>
<p>These can be viewed along with other note-worthy snippets of code from the application below.</p>
<h3 id="backbone">Backbone</h3>
-<h4 id="views-2">Views</h4>
+<h4 id="views-3">Views</h4>
<p>In our main application view (AppView), we want to load any previously stored Todo items in our Mongo database when the view initializes. This is done below with the line <code>Todos.fetch()</code> in the <code>initialize()</code> method where we also bind to the relevant events on the <code>Todos</code> collection for when items are added or changed.</p>
<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="co">// Our overall **AppView** is the top-level piece of UI.</span>
<span class="kw">var</span> AppView = <span class="kw">Backbone.View</span>.<span class="fu">extend</span>({
@@ -2475,7 +2631,7 @@ <h2 id="downloads-and-source-code">Downloads And Source Code</h2>
<li><p>Production: <a href="https://raw.github.com/addyosmani/backbone.baginator/master/dist/backbone.paginator.min.js">production</a></p></li>
<li><p>Development: <a href="https://raw.github.com/addyosmani/backbone.baginator/master/dist/backbone.paginator.js">development version</a></p></li>
<li><p>Examples + Source : <a href="https://github.com/addyosmani/backbone.paginator/zipball/v0.153">zipball</a></p></li>
-<li><p><a href="">Repository</a>http://github.com/addyosmani/backbone.paginator)</p></li>
+<li><p><a href="http://github.com/addyosmani/backbone.paginator">Repository</a></p></li>
</ul>
<h2 id="live-examples">Live Examples</h2>
<p>Live previews of both pagination components using the Netflix API can be found below. Download the tarball or fork the repository to experiment with these examples further.</p>
@@ -2599,7 +2755,7 @@ <h4 id="convenience-methods">Convenience methods:</h4>
<li><strong>Collection.howManyPer(n)</strong> - set the number of items to display per page</li>
</ul>
<h2 id="paginator.clientpager">Paginator.clientPager</h2>
-<p>The <code>clientPager</code> works similar to the <code>requestPager</code>, except that our configuration values influence the pagination of data already returned at a UI-level. Whilst not shown (yet) there is also a lot more UI logic that ties in with the <code>clientPager</code>. An example of this can be seen in ‘views/clientPagination.js.</p>
+<p>The <code>clientPager</code> works similar to the <code>requestPager</code>, except that our configuration values influence the pagination of data already returned at a UI-level. Whilst not shown (yet) there is also a lot more UI logic that ties in with the <code>clientPager</code>. An example of this can be seen in views/clientPagination.js.</p>
<h4 id="create-a-new-paginated-collection-with-a-model-and-url">1. Create a new paginated collection with a model and URL</h4>
<p>As with <code>requestPager</code>, let's first create a new Paginated <code>Backbone.Paginator.clientPager</code> collection, with a model and base URL:</p>
<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> PaginatedCollection = <span class="kw">Backbone.Paginator.clientPager</span>.<span class="fu">extend</span>({
@@ -2818,7 +2974,7 @@ <h3 id="getting-started-1">Getting started</h3>
<p>For this application, I opted for the nested namespacing pattern. Implemented correctly, this enables you to clearly identify if items being referenced in your app are views, other modules and so on. This initial structure is a sane place to also include application defaults (unless you prefer maintaining those in a separate file).</p>
<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">window</span>.<span class="fu">mobileSearch</span> = <span class="kw">window</span>.<span class="fu">mobileSearch</span> || {
<span class="dt">views</span>: {
- <span class="dt">appview</span>: <span class="kw">new</span> AppView
+ <span class="dt">appview</span>: <span class="kw">new</span> AppView()
},
<span class="dt">routers</span>:{
<span class="dt">workspace</span>:<span class="kw">new</span> Workspace()
@@ -2864,7 +3020,7 @@ <h2 id="introduction-2">Introduction</h2>
<h2 id="jasmine">Jasmine</h2>
<p>Jasmine describes itself as a behavior-driven development (BDD) framework for testing JavaScript code. Before we jump into how the framework works, it's useful to understand exactly what <a href="http://en.wikipedia.org/wiki/Behavior_Driven_Development">BDD</a> is.</p>
<p>BDD is a second-generation testing approach first described by <a href="http://dannorth.net/introducing-bdd/">Dan North</a> (the authority on BDD) which attempts to test the behavior of software. It's considered second-generation as it came out of merging ideas from Domain driven design (DDD) and lean software development, helping teams to deliver high quality software by answering many of the more confusing questions early on in the agile process. Such questions commonly include those concerning documentation and testing.</p>
-<p>If you were to read a book on BDD, it's likely to also be described as being 'outside-in and pull-based'. The reason for this is that it borrows the idea of of pulling features from Lean manufacturing which effectively ensures that the right software solutions are being written by a) focusing on expected outputs of the system and b) ensuring these outputs are achieved.</p>
+<p>If you were to read a book on BDD, it's likely to also be described as being 'outside-in and pull-based'. The reason for this is that it borrows the idea of pulling features from Lean manufacturing which effectively ensures that the right software solutions are being written by a) focusing on expected outputs of the system and b) ensuring these outputs are achieved.</p>
<p>BDD recognizes that there are usually multiple stakeholders in a project and not a single amorphous user of the system. These different groups will be affected by the software being written in differing ways and will have a varying opinion of what quality in the system means to them. It's for this reason that it's important to understand who the software will be bringing value you and exactly what in it will be valuable to them.</p>
<p>Finally, BDD relies on automation. Once you've defined the quality expected, your team will likely want to check on the functionality of the solution being built regularly and compare it to the results they expect. In order to facilitate this efficiently, the process has to be automated. BDD relies heavily on the automation of specification-testing and Jasmine is a tool which can assist with this.</p>
<p>BDD helps both developers and non-technical stakeholders:</p>
@@ -3208,7 +3364,7 @@ <h2 id="collections-2"><a name="testing-jasmine-collections">Collections</a></h2
}
});</code></pre>
-<h2 id="views-3"><a name="testing-jasmine-views">Views</a></h2>
+<h2 id="views-4"><a name="testing-jasmine-views">Views</a></h2>
<p>Before we take a look at testing Backbone views, let's briefly review a jQuery plugin that can assist with writing Jasmine specs for them.</p>
<p><strong>The Jasmine jQuery Plugin</strong></p>
<p>As we know our Todo application will be using jQuery for DOM manipulation, there's a useful jQuery plugin called <a href="https://github.com/velesin/jasmine-jquery">jasmine-jquery</a> we can use to help simplify BDD testing rendered elements that our views may produce.</p>
@@ -3321,7 +3477,7 @@ <h2 id="view-rendering">View rendering</h2>
&lt;/div&gt;
&lt;/div&gt;</code></pre>
<p>The second spec fails with the following message:</p>
-<p>Expected '' to contain <code>'&lt;label class=&quot;todo-content&quot;&gt;My Todo&lt;/label&gt;'</code>.</p>
+<p><code>Expected '' to contain '&lt;label class=&quot;todo-content&quot;&gt;My Todo&lt;/label&gt;'.</code></p>
<p>The reason for this is the default behavior for render() doesn't create any markup. Let's write a replacement for render() which fixes this:</p>
<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="dt">render</span>: <span class="kw">function</span>() {
<span class="kw">var</span> template = <span class="ch">&#39;&lt;label class=&quot;todo-content&quot;&gt;&lt;%= text %&gt;&lt;/label&gt;&#39;</span>;
@@ -3387,7 +3543,7 @@ <h2 id="rendering-with-a-templating-system">Rendering with a templating system</
});</code></pre>
<p>This will fail with the following message:</p>
-<p>Expected '<label class="todo-content">My Todo</label>' to have class 'done'.</p>
+<p><code>Expected '&lt;label class=&quot;todo-content&quot;&gt;My Todo&lt;/label&gt;' to have class 'done'.</code></p>
<p>which can be fixed in the existing render() method as follows:</p>
<pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="dt">render</span>: <span class="kw">function</span>() {
<span class="kw">var</span> template = <span class="ch">&#39;&lt;label class=&quot;todo-content&quot;&gt;&#39;</span> +
@@ -3454,7 +3610,7 @@ <h2 id="conclusions-1">Conclusions</h2>
<p>We have now covered how to write Jasmine tests for models, views and collections with Backbone.js. Whilst testing routing can at times be desirable, some developers feel it can be more optimal to leave this to third-party tools such as Selenium, so do keep this in mind.</p>
<p>James Newbery was kind enough to help me with writing the Views section above and his articles on <a href="http://tinnedfruit.com/2011/04/26/testing-backbone-apps-with-jasmine-sinon-3.html">Testing Backbone Apps With SinonJS</a> were of great inspiration (you'll actually find some Handlebars examples of the view specs in part 3 of his article). If you would like to learn more about writing spies and mocks for Backbone using <a href="http://sinonjs.org">SinonJS</a> as well as how to test Backbone routers, do consider reading his series.</p>
<h2 id="exercise">Exercise</h2>
-<p>As an exercise, I recommend now trying the Jasmine Koans in <code>practicals\jasmine-joans</code> and trying to fix some of the purposefully failing tests it has to offer. This is an excellent way of not just learning how Jasmine specs and suites work, but working through the examples (without peaking back) will also put your Backbone skills to test too.</p>
+<p>As an exercise, I recommend now trying the Jasmine Koans in <code>practicals\jasmine-joans</code> and trying to fix some of the purposefully failing tests it has to offer. This is an excellent way of not just learning how Jasmine specs and suites work, but working through the examples (without peeking back) will also put your Backbone skills to test too.</p>
<h2 id="further-reading">Further reading</h2>
<ul>
<li><a href="http://japhr.blogspot.com/2011/11/jasmine-backbonejs-revisited.html">Jasmine + Backbone Revisited</a></li>
@@ -4081,7 +4237,7 @@ <h3 id="collections-3">Collections</h3>
ok( <span class="kw">removeModelCallback</span>.<span class="fu">called</span> );
});</code></pre>
-<h3 id="views-4">Views</h3>
+<h3 id="views-5">Views</h3>
<p>For our views we want to ensure:</p>
<ul>
<li>They are being correctly tied to a DOM element when created</li>
View
264 index.md
@@ -510,8 +510,6 @@ It *is* however worth understanding where and why these concepts originated, so
-
-
## <a name="thebasics">The Basics</a>
---
@@ -531,6 +529,15 @@ Backbone's main benefits, regardless of your target platform or device, include
* Model data, views and routers in a succinct manner
* Provide DOM, model and collection synchronization
+## Is Backbone right for you?
+
+Does the following describe you?:
+
+"I want something flexible which offers a minimalist solution to separating concerns in my application. It should support a persistence layer and RESTful sync, models, views (with controllers), event-driven communication, templating and routing. It should be imperative, allowing one to update the View when a model changes. I’d like some decisions about the architecture left up to me. Ideally, many large companies have used the solution to build non-trivial applications.
+
+As I may be building something complex, I’d like there to be an active extension community around the framework that have already tried addressing larger problems (Marionette, Chaplin, Aura, Thorax). Ideally, there are also scaffolding tools (grunt-bbb, brunch) available for the solution."
+
+If so, continue reading.
##The Basics
@@ -542,6 +549,7 @@ In this section, you'll learn the essentials of Backbone's models, views, collec
* Views
* Namespacing
+
###<a name="thebasics-models" id="thebasics-models">Models</a>
Backbone models contain interactive 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 photo object including its attributes like tags, titles and a location.
@@ -710,6 +718,7 @@ myPhoto.setTitle('Fishing at sea');
//logs 'My title has been changed to.. Fishing at sea'
```
+
**Validation**
Backbone supports model validation through `Model.validate()`, which allows checking the attribute values for a model prior to them being set.
@@ -899,7 +908,36 @@ PhotoCollection.url = '/photos';
PhotoCollection.fetch();
```
-Under the covers, `Backbone.sync` is the function called every time Backbone tries to read or save models to the server. It uses jQuery or Zepto's ajax implementations to make these RESTful requests, however this can be overridden as per your needs.
+During configuration, Backbone sets a variable to denote if extended HTTP methods are supported by the server. Another setting controls if the server understands the correct MIME type for JSON:
+
+```javascript
+Backbone.emulateHTTP = false;
+Backbone.emulateJSON = false;
+```
+
+The Backbone.sync method that uses these values is actually an integral part of Backbone.js. A jQuery-like ajax method is assumed, so HTTP parameters are organised based on jQuery’s API. Searching through the code for calls to the sync method show it’s used whenever a model is saved, fetched, or deleted (destroyed).
+
+Under the covers, `Backbone.sync` is the function called every time Backbone tries to read or save models to the server. It uses jQuery or Zepto's ajax implementations to make these RESTful requests, however this can be overridden as per your needs. :
+
+The sync function may be overriden globally as Backbone.sync, or at a finer-grained level, by adding a sync function to a Backbone collection or to an individual model.
+
+There’s no fancy plugin API for adding a persistence layer – simply override Backbone.sync with the same function signature:
+
+```javascript
+Backbone.sync = function(method, model, options) {
+};
+```
+
+The default methodMap is useful for working out what the method argument does:
+
+```javascript
+var methodMap = {
+ 'create': 'POST',
+ 'update': 'PUT',
+ 'delete': 'DELETE',
+ 'read': 'GET'
+};
+```
In the above example if we wanted to log an event when `.sync()` was called, we could do this:
@@ -909,6 +947,7 @@ Backbone.sync = function(method, model) {
};
```
+
**Resetting/Refreshing Collections**
Rather than adding or removing models individually, you might occasionally wish to update an entire collection at once. `Collection.reset()` allows us to replace an entire collection with new models as follows:
@@ -1054,6 +1093,225 @@ zoomPhoto: function(factor){
}
```
+
+
+### Chainable API
+
+Another bit of sugar is the support for Underscore’s chain method. This works by calling the original method with the current array of models and returning the result. In case you haven’t seen it before, the chainable API looks like this:
+
+```javascript
+var collection = new Backbone.Collection([
+ { name: 'Tim', age: 5 },
+ { name: 'Ida', age: 26 },
+ { name: 'Rob', age: 55 }
+]);
+
+collection.chain()
+ .filter(function(item) { return item.get('age') > 10; })
+ .map(function(item) { return item.get('name'); })
+ .value();
+
+// Will return ['Ida', 'Rob']
+Some of the Backbone-specific method will return this, which means they can be chained as well:
+
+var collection = new Backbone.Collection();
+
+collection
+ .add({ name: 'John', age: 23 })
+ .add({ name: 'Harry', age: 33 })
+ .add({ name: 'Steve', age: 41 });
+
+collection.pluck('name');
+// ['John', 'Harry', 'Steve']
+```
+
+
+### Backbone’s inheritance Implementation
+
+The comments indicate that the inherits function is inspired by goog.inherits. Google’s implementation is from the Closure Library, but Backbone’s API accepts two objects (incorrectly referred to as a hash) containing “instance” and “static” methods. Each of Backbone’s objects has an extend method:
+
+Model.extend = Collection.extend = Router.extend = View.extend = extend;
+Most development with Backbone is based around inheriting from these objects, and they’re designed to mimic a classical object-oriented implementation.
+
+Backbone uses Underscore’s extend method:
+
+```javascript
+each(slice.call(arguments, 1), function(source) {
+ for (var prop in source) {
+ obj[prop] = source[prop];
+ }
+});
+
+return obj;
+```
+
+This isn’t the same as ES5’s Object.create, it’s actually copying properties (methods and values) from one object to another. Since this isn’t enough to support Backbone’s inheritance and class model, the following steps are performed:
+
+* The instance methods are checked to see if there’s a constructor property. If so, the class’s constructor is used, otherwise the parent’s constructor is used (i.e., Backbone.Model)
+
+* Underscore’s extend method is called to add the parent class’s methods to the new child class
+The prototype property of a blank constructor function is assigned with the parent’s prototype, and a new instance of this is set to the child’s prototype property
+
+* Underscore’s extend method is called twice to add the static and instance methods to the child class
+
+* The child’s prototype’s constructor and a __super__ property are assigned
+
+This pattern is also used for classes in CoffeeScript, so Backbone classes are compatible with CoffeeScript classes.
+
+
+
+### Backbone’s Sync API
+
+The Backbone.sync method is intended to be overridden to support other backends. The built-in method is tailed to a certain breed of RESTful JSON APIs – Backbone was originally extracted from a Ruby on Rails application, which uses HTTP methods like PUT the same way.
+
+The way this works is the model and collection classes have a sync method that calls Backbone.sync. Both will call this.sync internally when fetching, saving, or deleting items.
+
+The sync method is called with three parameters:
+
+* method: One of create, update, delete, read
+* model: The Backbone model object
+* options: May include success and error methods
+
+Implementing a new sync method can use the following pattern:
+
+```javascript
+Backbone.sync = function(method, model, options) {
+ var requestContent = {}, success, error;
+
+ function success(result) {
+ // Handle results from MyAPI
+ if (options.success) {
+ options.success(result);
+ }
+ }
+
+ function error(result) {
+ // Handle results from MyAPI
+ if (options.error) {
+ options.error(result);
+ }
+ }
+
+ options || (options = {});
+
+ switch (method) {
+ case 'create':
+ requestContent['resource'] = model.toJSON();
+ return MyAPI.create(model, success, error);
+
+ case 'update':
+ requestContent['resource'] = model.toJSON();
+ return MyAPI.update(model, success, error);
+
+ case 'delete':
+ return MyAPI.destroy(model, success, error);
+
+ case 'read':
+ if (model.attributes[model.idAttribute]) {
+ return MyAPI.find(model, success, error);
+ } else {
+ return MyAPI.findAll(model, success, error);
+ }
+ }
+};
+```
+
+This pattern delegates API calls to a new object, which could be a Backbone-style class that supports events. This can be safely tested separately, and potentially used with libraries other than Backbone.
+
+There are quite a few sync implementations out there:
+
+* Backbone localStorage
+* Backbone offline
+* Backbone Redis
+* backbone-parse
+* backbone-websql
+* Backbone Caching Sync
+
+### Conflict Management
+
+Like most client-side projects, Backbone.js wraps everything in an immediately-invoked function expression:
+
+```javascript
+(function(){
+ // Backbone.js
+}).call(this);
+```
+
+Several things happen during this configuration stage. A Backbone “namespace” is created, and multiple versions of Backbone on the same page are supported through the noConflict mode:
+
+```javascript
+var root = this;
+var previousBackbone = root.Backbone;
+
+Backbone.noConflict = function() {
+ root.Backbone = previousBackbone;
+ return this;
+};
+```
+
+Multiple versions of Backbone can be used on the same page by calling noConflict like this:
+
+```javascript
+var Backbone19 = Backbone.noConflict();
+// Backbone19 refers to the most recently loaded version,
+// and `window.Backbone` will be restored to the previously
+// loaded version
+```
+
+This initial configuration code also supports CommonJS modules so Backbone can be used in Node projects:
+
+```javascript
+var Backbone;
+if (typeof exports !== 'undefined') {
+ Backbone = exports;
+} else {
+ Backbone = root.Backbone = {};
+}
+```
+
+The existence of Underscore.js (also by DocumentCloud) and a jQuery-like library is checked as well.
+
+
+### Leverage Events
+
+Backbone’s classes are designed to be inherited from. Every single one of these classes inherits from Backbone.Events:
+
+* Backbone.Model
+* Backbone.Collection
+* Backbone.Router
+* Backbone.History
+* Backbone.View
+
+That means when designing applications built with Backbone, events are a key architectural component. Events are the standard way to deal with user interface actions, through the declarative event bindings on views, and also model and collection changes. However, you can easily add your own custom events.
+
+When learning Backbone it’s important to get a feel for the built-in event names. Incorrectly binding a collection reset event, for example, could cause your application to render more often than it should. Mastering events is one of the quickest ways to become more productive with Backbone.
+
+#### Underscore.js
+
+Since Backbone depends on Underscore, it’s worth keeping this in mind when dealing with any kind of arrays or collections of data. Also, familiarity with Underscore’s methods will help work with Backbone.Collection effectively.
+
+#### Views
+
+It’s easy to slip into using $, but avoid this where possible. Backbone caches a view’s element, so use this.$el instead. Design views based on the single responsibility principle.
+
+It might be tempting to let “container” view render HTML directly by using $().html, but resisting the temptation and creating a hierarchy of views will make it much easier to debug your code and write automated tests.
+
+Interestingly, Backbone doesn’t have a lot of code dedicated to templates, but it can work with the template method. I use this with RequireJS text file dependencies to load remote templates during development, then I use the RequireJS build script to generate something suitable for deployment. This makes code easy to test and fast to load.
+
+#### API Style
+
+Backbone’s API is thankfully very consistent. Even the history API accepts a silent option, which is used throughout the library to stop events from firing when they’re not required.
+
+Backbone’s collections have Underscore’s chainable API, which can be handy, but care must be taken to use this correctly.
+
+#### Testing Backbone
+
+So far we’ve been reviewing Backbone’s code to demystify the framework as a whole. However, it’s worth noting that other technologies work very well with Backbone and Underscore. RequireJS and AMD modules can be a great way to break up projects.
+
+However, one area that Backbone doesn’t address is testing. This is unfortunate, because testing Backbone projects definitely isn’t obvious. Later in the book we'll look at testing in more detail.
+
+
+
###<a name="thebasics-namespacing" id="thebasics-namespacing">Namespacing</a>
When learning how to use Backbone, an important and commonly overlooked area by tutorials is namespacing. If you already have experience with namespacing in JavaScript, the following section will provide some advice on how to specifically apply concepts you know to Backbone, however I will also be covering explanations for beginners to ensure everyone is on the same page.
Please sign in to comment.
Something went wrong with that request. Please try again.