Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tag: v0.9
Fetching contributors…

Cannot retrieve contributors at this time

10017 lines (9502 sloc) 387.744 kb
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<article>
<articleinfo>
<title></title>
</articleinfo>
<sect1 id="prelude">
<title>Prelude</title>
<para>
Welcome to my (in-progress) book about the
<ulink url="http://documentcloud.github.com/backbone/">Backbone.js</ulink>
framework for structuring JavaScript applications. It’s released
under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0
Unported
<ulink url="http://creativecommons.org/licenses/by-nc-sa/3.0/">license</ulink>
meaning you can both grab a copy of the book for free or help to
further
<ulink url="https://github.com/addyosmani/backbone-fundamentals/">improve</ulink>
it.
</para>
<para>
I’m very pleased to announce that this book will be out in physical
form in a few months time via
<ulink url="http://oreilly.com">O’Reilly Media</ulink>. Readers will
have the option of purchasing the latest version in either print or
a number of digital formats then or can grab a recent version from
this repository.
</para>
<para>
Corrections to existing material are always welcome and I hope that
together we can provide the community with an up-to-date resource
that is of help. My extended thanks go out to
<ulink url="https://github.com/jashkenas">Jeremy Ashkenas</ulink>
for creating Backbone.js and
<ulink url="https://github.com/addyosmani/backbone-fundamentals/contributors">these</ulink>
members of the community for their assistance tweaking this project.
</para>
<para>
I hope you find this book helpful!
</para>
</sect1>
<sect1 id="table-of-contents">
<title>Table Of Contents</title>
<itemizedlist>
<listitem>
</listitem>
<listitem>
<itemizedlist>
<listitem>
<para>
<link linkend="mvc-mvp">MVC, MVP &amp; Backbone.js</link>
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<itemizedlist>
<listitem>
<para>
<link linkend="models">Models</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="views">Views</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="collections">Collections</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="routers">Routers</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="namespacing">Namespacing</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="additional-tips">Additional tips</link>
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<itemizedlist>
<listitem>
<para>
<link linkend="restful">Building RESTful applications with
Backbone</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="stack1">Building Backbone apps with Node.js,
Express, Mongoose and MongoDB</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="stack2">Building Backbone apps with Ruby,
Sinatra, Haml and MongoDB</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="pagination">Paginating Backbone.js Requests
&amp; Collections</link>
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<itemizedlist>
<listitem>
<para>
<link linkend="modularjs">Modular JavaScript</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="organizingmodules">Organizing modules with
RequireJS and AMD</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="externaltemplates">Keeping your templates
external with the RequireJS text plugin</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="optimizingrequirejs">Optimizing Backbone apps
for production with the RequireJS Optimizer</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="practicalrequirejs">Practical: Building a
modular Backbone app with AMD &amp; RequireJS</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="decouplingbackbone">Decoupling Backbone with
the Mediator and Facade patterns</link>
</para>
</listitem>
<listitem>
<para>
Backbone &amp; jQuery Mobile
</para>
</listitem>
<listitem>
<para>
Practical: Building A Modular Mobile App With Backbone &amp;
jQuery Mobile
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<itemizedlist>
<listitem>
<para>
<link linkend="unittestingjasmine">Unit Testing Backbone
Applications With Jasmine</link>
</para>
</listitem>
<listitem>
<para>
Introduction
</para>
</listitem>
<listitem>
<para>
Jasmine
</para>
<itemizedlist>
<listitem>
<para>
Suites, Specs And Spies
</para>
</listitem>
<listitem>
<para>
TDD With Backbone
</para>
</listitem>
<listitem>
<para>
<link linkend="testing-jasmine-models">Testing
Models</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="testing-jasmine-collections">Testing
Collections</link>
</para>
</listitem>
<listitem>
<para>
<link linkend="testing-jasmine-views">Testing
Views</link>
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
<link linkend="unittestingqunit">Unit Testing Backbone
Applications With QUnit And SinonJS</link>
</para>
</listitem>
<listitem>
<para>
Introduction
</para>
</listitem>
<listitem>
<para>
QUnit
</para>
<itemizedlist>
<listitem>
<para>
Assertions
</para>
</listitem>
<listitem>
<para>
Adding structure to assertions
</para>
</listitem>
<listitem>
<para>
Assertion examples
</para>
</listitem>
<listitem>
<para>
Fixtures
</para>
</listitem>
<listitem>
<para>
Asynchronous code
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
SinonJS
</para>
<itemizedlist>
<listitem>
<para>
Stubs
</para>
</listitem>
<listitem>
<para>
Mocks
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
Practical
</para>
<itemizedlist>
<listitem>
<para>
Testing Models
</para>
</listitem>
<listitem>
<para>
Testing Collections
</para>
</listitem>
<listitem>
<para>
Testing Views
</para>
</listitem>
<listitem>
<para>
Testing Events
</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</listitem>
<listitem>
</listitem>
</itemizedlist>
</sect1>
<sect1 id="introduction">
<title><a name="introduction">Introduction</a></title>
<para>
As JavaScript developers, we are at an interesting point in time
where not only do we have mature solutions to help organize the
JavaScript powering our applications based on a separation of
concerns, but developers looking to build non-trivial projects are
almost spoiled for choice for frameworks that can help structure
their applications.
</para>
<para>
Maturity in software (framework) development isn’t simply about how
long a framework has been around. It’s about how solid the framework
is and more importantly how well it’s evolved to fill its role. Has
it become more effective at solving common problems? Does it
continue to improve as developers build larger and more complex
applications with it?
</para>
<para>
In this book, I will be covering the popular Backbone.js, which I
consider the best of the current family of JavaScript architectural
frameworks.
</para>
<para>
Topics will include MVC theory and how to build applications using
Backbone’s models, views, collections and routers. I’ll also be
taking you through advanced topics like modular development with
Backbone.js and AMD (via RequireJS), how to build applications using
modern software stacks (like Node and Express), how to solve the
routing problems with Backbone and jQuery Mobile, tips about
scaffolding tools, and a lot more.
</para>
<para>
If this is your first time looking at Backbone.js and you’re still
unsure whether or not to give it a try, why not take a look at how
<ulink url="http://github.com/addyosmani/todomvc">a Todo
application</ulink> can be implemented in Backbone and several other
popular Javascript frameworks before reading further?
</para>
<para>
The goal of this book is to create an authoritative and centralized
repository of information that can help those developing real-world
apps with Backbone. If you come across a section or topic which you
think could be improved or expanded on, please feel free to submit a
pull-request. It won’t take long and you’ll be helping other
developers avoid problems you’ve run into before.
</para>
</sect1>
<sect1 id="fundamentals">
<title><a name="fundamentals">Fundamentals</a></title>
<para>
In this section we are going to cover the context into which a
framework like Backbone.js fits. Let’s begin our journey into
understanding Backbone better with a look at code architecture.
</para>
<sect2 id="mvc-mvp-backbone.js">
<title><a name="mvc-mvp">MVC, MVP &amp; Backbone.js</a></title>
<para>
Before exploring any JavaScript frameworks that assist in
structuring applications, it can be useful to gain a basic
understanding of architectural design patterns. Design patterns
are proven solutions to common development problems and can
suggest structural approaches to help guide developers in adding
some organization to their applications.
</para>
<para>
Patterns are useful because they’re a set of practices that build
upon the collective experience of skilled developers who have
repeatedly solved similar problems. Although developers 10 or 20
years ago may not have been using the same programming languages
when implementing patterns in their projects, there are many
lessons we can learn from their efforts.
</para>
<para>
In this section, we’re going to review two popular patterns - MVC
and MVP. We’ll be exploring in greater detail how Backbone.js
implements these patterns shortly to better appreciate where it
fits in.
</para>
</sect2>
</sect1>
<sect1 id="mvc">
<title>MVC</title>
<para>
MVC (Model-View-Controller) is an architectural design pattern that
encourages improved application organization through a separation of
concerns. It enforces the isolation of business data (Models) from
user interfaces (Views), with a third component (Controllers)
traditionally present to manage logic, user-input and the
coordination of models and views. The pattern was originally
designed by
<ulink url="http://en.wikipedia.org/wiki/Trygve_Reenskaug">Trygve
Reenskaug</ulink> while working on Smalltalk-80 (1979), where it was
initially called Model-View-Controller-Editor. MVC was described in
depth in
<ulink url="http://www.amazon.co.uk/Design-patterns-elements-reusable-object-oriented/dp/0201633612"><quote>Design
Patterns: Elements of Reusable Object-Oriented
Software</quote></ulink> (The <quote>GoF</quote> or <quote>Gang of
Four</quote> book) in 1994, which played a role in popularizing its
use.
</para>
<sect2 id="smalltalk-80-mvc">
<title>Smalltalk-80 MVC</title>
<para>
It’s important to understand what the original MVC pattern was
aiming to solve as it has changed quite heavily since the days of
its origin. Back in the 70’s, graphical user-interfaces were far
and few between. An approach known as
<ulink url="http://martinfowler.com/eaaDev/uiArchs.html">Separated
Presentation</ulink> began to be used as a means to make a clear
division between domain objects which modeled concepts in the real
world (e.g a photo, a person) and the presentation objects which
were rendered to the user’s screen.
</para>
<para>
The Smalltalk-80 implementation of MVC took this concept further
and had an objective of separating out the application logic from
the user interface. The idea was that decoupling these parts of
the application would also allow the reuse of models for other
interfaces in the application. There are some interesting points
worth noting about Smalltalk-80’s MVC architecture:
</para>
<itemizedlist>
<listitem>
<para>
A Domain element was known as a Model and were ignorant of the
user-interface (Views and Controllers)
</para>
</listitem>
<listitem>
<para>
Presentation was taken care of by the View and the Controller,
but there wasn’t just a single view and controller. A
View-Controller pair was required for each element being
displayed on the screen and so there was no true separation
between them
</para>
</listitem>
<listitem>
<para>
The Controller’s role in this pair was handling user input
(such as key-presses and click events), doing something
sensible with them.
</para>
</listitem>
<listitem>
<para>
The Observer pattern was relied upon for updating the View
whenever the Model changed
</para>
</listitem>
</itemizedlist>
<para>
Developers are sometimes surprised when they learn that the
Observer pattern (nowadays commonly implemented as a
Publish/Subscribe system) was included as a part of MVC’s
architecture decades ago. In Smalltalk-80’s MVC, the View and
Controller both observe the Model: anytime the Model changes, the
Views react. A simple example of this is an application backed by
stock market data - for the application to show real-time
information, any change to the data in its Models should result in
the View being refreshed instantly.
</para>
<para>
Martin Fowler has done an excellent job of writing about the
<ulink url="http://martinfowler.com/eaaDev/uiArchs.html">origins</ulink>
of MVC over the years and if you are interested in further
historical information about Smalltalk-80’s MVC, I recommend
reading his work.
</para>
</sect2>
</sect1>
<sect1 id="mvc-as-we-know-it">
<title>MVC As We Know It</title>
<para>
We’ve reviewed the 70’s, but let us now return to the here and now.
The MVC pattern has been applied to a diverse range of programming
languages. For example, the popular Ruby on Rails is an
implementation of a web application framework based on MVC for the
Ruby language. JavaScript now has a number of MVC frameworks,
including Ember.js, JavaScriptMVC, and of course Backbone.js. Given
the importance of avoiding <quote>spaghetti</quote> code, a term
which describes code that is very difficult to read or maintain due
to its lack of structure, let’s look at what the MVC pattern enables
the Javascript developer to do.
</para>
<para>
MVC is composed of three core components:
</para>
<sect2 id="models">
<title>Models</title>
<para>
Models manage the data for an application. They are concerned with
neither the user-interface nor presentation layers, but instead
represent structured data that an application may require. When a
model changes (e.g when it is updated), it will typically notify
its observers (e.g views, a concept we will cover shortly) that a
change has occurred so that they may react accordingly.
</para>
<para>
To understand models better, let us imagine we have a JavaScript
photo gallery application. In a photo gallery, a photo would merit
its own model, as it represents a unique kind of domain-specific
data. The Photo model may represent attributes such as a caption,
image source and additional meta-data. A specific photo would be
stored in an instance of a model. Here’s an example of a simple
Photo model implemented with Backbone.js:
</para>
<programlisting language="javascript">
var Photo = Backbone.Model.extend({
// Default attributes for the photo
defaults: {
// Ensure that each photo created has an `src`.
src: &quot;placeholder.jpg&quot;,
caption: &quot;A default image&quot;,
viewed: false
},
initialize: function() {
}
});
</programlisting>
<para>
The built-in capabilities of models vary across frameworks,
however it’s common for them to support validation of attributes,
where attributes represent the properties of the model, such as a
model identifier. When using models in real-world applications we
generally also need a way of persisting models. Persistence allows
us to edit and update models with the knowledge that their most
recent states will be saved somewhere, for example in a web
browser’s localStorage data-store or synchronized with a database.
</para>
<para>
A model may also have multiple views observing it. Imagine our
Photo model contained meta-data such as the longitude and latitude
where the photo was taken, a list of people present in the photo,
and a list of tags. A developer could create a single view that
displayed all these attributes, or might create three separate
views to display each attribute. The important detail is that the
Photo model doesn’t care how these views are organized, it simply
announces updates to its data as necessary. We’ll come back to
Views in more detail later.
</para>
<para>
It is not uncommon for modern MVC/MV* frameworks to provide a
means to group models together. In Backbone, these groups are
called <quote>Collections</quote>. Managing models in groups
allows us to write application logic based on notifications from
the group, should any model it contains change. This avoids the
need to manually observe individual model instances.
</para>
<para>
Here’s how we might group Photo models into a simplified Backbone
Collection:
</para>
<programlisting language="javascript">
var PhotoGallery = Backbone.Collection.extend({
// Reference to this collection's model.
model: Photo,
// Filter down the list of all photos that have been viewed
viewed: function() {
return this.filter(function(photo){ return photo.get('viewed'); });
},
// Filter down the list to only photos that have not yet been viewed
unviewed: function() {
return this.without.apply(this, this.viewed());
}
});
</programlisting>
<para>
If you read older texts on MVC, you may come across a description
of models as also managing application <quote>state</quote>. In
JavaScript applications <quote>state</quote> has a specific
meaning, typically referring to the current <quote>state</quote>
of a view or sub-view on a user’s screen at a fixed time. State is
a topic which is regularly discussed when looking at Single-page
applications, where the concept of state needs to be simulated.
</para>
</sect2>
<sect2 id="views">
<title>Views</title>
<para>
Views are a visual representation of models that present a
filtered view of their current state. A view typically observes a
model and is notified when the model changes, allowing the view to
update itself accordingly. Design pattern literature commonly
refers to views as <quote>dumb</quote>, given that their knowledge
of models and controllers in an application is limited.
</para>
<para>
Users interact with views, which usually means reading and editing
model data. For example, in our photo gallery application example,
model viewing might happen in a user interface with a big image, a
caption, and a list of tags. Model editing could be done through
an <quote>edit</quote> view where a user who has selected a
specific photo could edit its caption, tags, or other metadata in
a form.
</para>
<para>
In MVC, the actual task of updating the Model falls to
Controllers, which we’ll be covering shortly.
</para>
<para>
Let’s explore Views a little further using a simple JavaScript
example. Below we can see a function that creates a single Photo
view, consuming both a model instance and a controller instance.
</para>
<para>
We define a <literal>render()</literal> utility within our view
which is responsible for rendering the contents of the
<literal>photoModel</literal> using a JavaScript templating engine
(Underscore templating) and updating the contents of our view,
referenced by <literal>photoEl</literal>.
</para>
<para>
The <literal>photoModel</literal> then adds our
<literal>render()</literal> callback as one of its subscribers, so
that through the Observer pattern it can trigger the view to
update when the model changes.
</para>
<para>
You may wonder where user interaction comes into play here. When
users click on any elements within the view, it’s not the view’s
responsibility to know what to do next. A Controller makes this
decision. In our sample implementation, this is achieved by adding
an event listener to <literal>photoEl</literal> which will
delegate handling the click behavior back to the controller,
passing the model information along with it in case it’s needed.
</para>
<para>
The benefit of this architecture is that each component plays its
own separate role in making the application function as needed.
</para>
<programlisting language="javascript">
var buildPhotoView = function( photoModel, photoController ){
var base = document.createElement('div'),
photoEl = document.createElement('div');
base.appendChild(photoEl);
var render= function(){
// We use a templating library such as Underscore
// templating which generates the HTML for our
// photo entry
photoEl.innerHTML = _.template('photoTemplate', {src: photoModel.getSrc()});
}
photoModel.addSubscriber( render );
photoEl.addEventListener('click', function(){
photoController.handleEvent('click', photoModel );
});
var show = function(){
photoEl.style.display = '';
}
var hide = function(){
photoEl.style.display = 'none';
}
return{
showView: show,
hideView: hide
}
}
</programlisting>
<para>
<emphasis role="strong">Templating</emphasis>
</para>
<para>
In the context of JavaScript frameworks that support MVC/MV*, it
is worth looking more closely at JavaScript templating and its
relationship to Views.
</para>
<para>
It has long been considered bad practice (and computationally
expensive) to manually create large blocks of HTML markup
in-memory through string concatenation. Developers using this
technique often find themselves iterating through their data,
wrapping it in nested divs and using outdated techniques such as
<literal>document.write</literal> to inject the
<quote>template</quote> into the DOM. This approach often means
keeping scripted markup inline with standard markup, which can
quickly become difficult to read and maintain, especially when
building large applications.
</para>
<para>
JavaScript templating libraries (such as Handlebars.js or
Mustache) are often used to define templates for views as HTML
markup containing template variables. These template blocks can be
either stored externally or within script tags with a custom type
(e.g <quote>text/template</quote>). Variables are deliminated
using a variable syntax (e.g {{name}}). Javascript template
libraries typically accept data in JSON, and the grunt work of
populating templates with data is taken care of by the framework
itself. This has a several benefits, particularly when opting to
store templates externally as this can let applications load
templates dynamically on an as-needed basis.
</para>
<para>
Let’s compare two examples of HTML templates. One is implemented
using the popular Handlebars.js library, and the other uses
Underscore’s <quote>microtemplates</quote>.
</para>
<para>
<emphasis role="strong">Handlebars.js:</emphasis>
</para>
<programlisting language="html">
&lt;li class=&quot;photo&quot;&gt;
&lt;h2&gt;{{caption}}&lt;/h2&gt;
&lt;img class=&quot;source&quot; src=&quot;{{src}}&quot;/&gt;
&lt;div class=&quot;meta-data&quot;&gt;
{{metadata}}
&lt;/div&gt;
&lt;/li&gt;
</programlisting>
<para>
<emphasis role="strong">Underscore.js Microtemplates:</emphasis>
</para>
<programlisting language="html">
&lt;li class=&quot;photo&quot;&gt;
&lt;h2&gt;&lt;%= caption %&gt;&lt;/h2&gt;
&lt;img class=&quot;source&quot; src=&quot;&lt;%= src %&gt;&quot;/&gt;
&lt;div class=&quot;meta-data&quot;&gt;
&lt;%= metadata %&gt;
&lt;/div&gt;
&lt;/li&gt;
</programlisting>
<para>
You may also use double curly brackets (i.e
<literal>{{}}</literal>) (or any other tag you feel comfortable
with) in Microtemplates. In the case of curly brackets, this can
be done by setting the Underscore
<literal>templateSettings</literal> attribute as follows:
</para>
<programlisting language="javascript">
_.templateSettings = { interpolate : /\{\{(.+?)\}\}/g };
</programlisting>
<para>
<emphasis role="strong">A note on navigation and state</emphasis>
</para>
<para>
It is also worth noting that in classical web development,
navigating between independent views required the use of a page
refresh. In single-page JavaScript applications, however, once
data is fetched from a server via Ajax, it can be dynamically
rendered in a new view within the same page. Since this doesn’t
automatically update the URL, the role of navigation thus falls to
a <quote>router</quote>, which assists in managing application
state (e.g allowing users to bookmark a particular view they have
navigated to). As routers are however neither a part of MVC nor
present in every MVC-like framework, I will not be going into them
in greater detail in this section.
</para>
</sect2>
<sect2 id="controllers">
<title>Controllers</title>
<para>
Controllers are an intermediary between models and views which are
classically responsible for two tasks: they both update the view
when the model changes and update the model when the user
manipulates the view.
</para>
<para>
In our photo gallery application, a controller would be
responsible for handling changes the user made to the edit view
for a particular photo, updating a specific photo model when a
user has finished editing.
</para>
<para>
It’s with controllers that most JavaScript MVC frameworks depart
from this interpretation of the MVC pattern. The reasons for this
vary, but in my opinion, Javascript framework authors likely
initially looked at server-side interpretations of MVC (such as
Ruby on Rails), realized that that approach didn’t translate 1:1
on the client-side, and so re-interpreted the C in MVC to solve
their state management problem. This was a clever approach, but it
can make it hard for developers coming to MVC for the first time
to understand both the classical MVC pattern and the
<quote>proper</quote> role of controllers in other non-Javascript
frameworks.
</para>
<para>
So does Backbone.js have Controllers? Not really. Backbone’s Views
typically contain <quote>controller</quote> logic, and Routers
(discussed below) are used to help manage application state, but
neither are true Controllers according to classical MVC.
</para>
<para>
In this respect, contrary to what might be mentioned in the
official documentation or in blog posts, Backbone is neither a
truly MVC/MVP nor MVVM framework. It’s in fact better to see it a
member of the MV* family which approaches architecture in its own
way. There is of course nothing wrong with this, but it is
important to distinguish between classical MVC and MV* should you
be relying on discussions of MVC to help with your Backbone
projects.
</para>
</sect2>
<sect2 id="controllers-in-spine.js-vs-backbone.js">
<title>Controllers in Spine.js vs Backbone.js</title>
<para>
<emphasis role="strong">Spine.js</emphasis>
</para>
<para>
We now know that controllers are traditionally responsible for
updating the view when the model changes (and similarly the model
when the user updates the view). Since Backbone doesn’t have its
<emphasis role="strong">own</emphasis> explicit controllers, it’s
useful to review the controller from another MVC framework to
appreciate the difference in implementations. Let’s take a look at
<ulink url="http://spinejs.com/">Spine.js</ulink>:
</para>
<para>
In this example, we’re going to have a controller called
<literal>PhotosController</literal> which will be in charge of
individual photos in the application. It will ensure that when the
view updates (e.g a user edited the photo meta-data) the
corresponding model does too.
</para>
<para>
(Note: We won’t be delving heavily into Spine.js beyond this
example, but it’s worth looking at it to learn more about
Javascript frameworks in general.)
</para>
<programlisting language="javascript">
// Controllers in Spine are created by inheriting from Spine.Controller
var PhotosController = Spine.Controller.sub({
init: function(){
this.item.bind(&quot;update&quot;, this.proxy(this.render));
this.item.bind(&quot;destroy&quot;, this.proxy(this.remove));
},
render: function(){
// Handle templating
this.replace($(&quot;#photoTemplate&quot;).tmpl(this.item));
return this;
},
remove: function(){
this.el.remove();
this.release();
}
});
</programlisting>
<para>
In Spine, controllers are considered the glue for an application,
adding and responding to DOM events, rendering templates and
ensuring that views and models are kept in sync (which makes sense
in the context of what we know to be a controller).
</para>
<para>
What we’re doing in the above example is setting up listeners in
the <literal>update</literal> and <literal>destroy</literal>
events using <literal>render()</literal> and
<literal>remove()</literal>. When a photo entry gets updated, we
re-render the view to reflect the changes to the meta-data.
Similarly, if the photo gets deleted from the gallery, we remove
it from the view. In case you were wondering about the
<literal>tmpl()</literal> function in the code snippet: in the
<literal>render()</literal> function, we’re using this to render a
JavaScript template called #photoTemplate which simply returns a
HTML string used to replace the controller’s current element.
</para>
<para>
What this provides us with is a very lightweight, simple way to
manage changes between the model and the view.
</para>
<para>
<emphasis role="strong">Backbone.js</emphasis>
</para>
<para>
Later on in this section we’re going to revisit the differences
between Backbone and traditional MVC, but for now let’s focus on
controllers.
</para>
<para>
In Backbone, controller logic is shared between Backbone.View and
Backbone.Router. Earlier releases of Backbone contained something
called Backbone.Controller, but it was renamed to Router to
clarify its role.
</para>
<para>
A Router’s main purpose is to translate URL requests into
application states. When a user browses to the URL
www.example.com/photos/42, a Router could be used to show the
photo with that ID, and to define what application behavior should
be run in response to that request. Routers
<emphasis>can</emphasis> contain traditional controller
responsibilities, such as binding the events between models and
views, or rendering parts of the page. However, Backbone
contributor Tim Branyen has pointed out that it’s possible to get
away without needing Backbone.Router at all for this, so a way to
think about it using the Router paradigm is probably:
</para>
<programlisting language="javascript">
var PhotoRouter = Backbone.Router.extend({
routes: { &quot;photos/:id&quot;: &quot;route&quot; },
route: function(id) {
var item = photoCollection.get(id);
var view = new PhotoView({ model: item });
something.html( view.render().el );
}
}):
</programlisting>
</sect2>
</sect1>
<sect1 id="what-does-mvc-give-us">
<title>What does MVC give us?</title>
<para>
To summarize, the separation of concerns in MVC facilitates
modularization of an application’s functionality and enables:
</para>
<itemizedlist>
<listitem>
<para>
Easier overall maintenance. When updates need to be made to the
application it is clear whether the changes are data-centric,
meaning changes to models and possibly controllers, or merely
visual, meaning changes to views.<literallayout></literallayout>
</para>
</listitem>
<listitem>
<para>
Decoupling models and views means that it’s straight-forward to
write unit tests for business
logic<literallayout></literallayout>
</para>
</listitem>
<listitem>
<para>
Duplication of low-level model and controller code is eliminated
across the application
</para>
</listitem>
<listitem>
<para>
Depending on the size of the application and separation of
roles, this modularity allows developers responsible for core
logic and developers working on the user-interfaces to work
simultaneously
</para>
</listitem>
</itemizedlist>
<sect2 id="delving-deeper">
<title>Delving deeper</title>
<para>
Right now, you likely have a basic understanding of what the MVC
pattern provides, but for the curious, we’ll explore it a little
further.
</para>
<para>
The GoF (Gang of Four) do not refer to MVC as a design pattern,
but rather consider it a <quote>set of classes to build a user
interface</quote>. In their view, it’s actually a variation of
three other classical design patterns: the Observer (Pub/Sub),
Strategy and Composite patterns. Depending on how MVC has been
implemented in a framework, it may also use the Factory and
Decorator patterns. I’ve covered some of these patterns in my
other free book, JavaScript Design Patterns For Beginners if you
would like to read into them further.
</para>
<para>
As we’ve discussed, models represent application data, while views
handle what the user is presented on screen. As such, MVC relies
on Pub/Sub for some of its core communication (something that
surprisingly isn’t covered in many articles about the MVC
pattern). When a model is changed it <quote>publishes</quote> to
the rest of the application that it has been updated. The
<quote>subscriber</quote>–generally a Controller–then updates the
view accordingly. The observer-viewer nature of this relationship
is what facilitates multiple views being attached to the same
model.
</para>
<para>
For developers interested in knowing more about the decoupled
nature of MVC (once again, depending on the implementation), one
of the goals of the pattern is to help define one-to-many
relationships between a topic and its observers. When a topic
changes, its observers are updated. Views and controllers have a
slightly different relationship. Controllers facilitate views to
respond to different user input and are an example of the Strategy
pattern.
</para>
</sect2>
<sect2 id="summary">
<title>Summary</title>
<para>
Having reviewed the classical MVC pattern, your should now
understand how it allows developers to cleanly separate concerns
in an application. You should also now appreciate how JavaScript
MVC frameworks may differ in their interpretation of MVC, and how
they share some of the fundamental concepts of the original
pattern.
</para>
<para>
When reviewing a new JavaScript MVC/MV* framework, remember - it
can be useful to step back and consider how it’s opted to approach
Models, Views, Controllers or other alternatives, as this can
better help you grok how the framework expects to be used.
</para>
</sect2>
</sect1>
<sect1 id="mvp">
<title>MVP</title>
<para>
Model-view-presenter (MVP) is a derivative of the MVC design pattern
which focuses on improving presentation logic. It originated at a
company named
<ulink url="http://en.wikipedia.org/wiki/Taligent">Taligent</ulink>
in the early 1990s while they were working on a model for a C++
CommonPoint environment. Whilst both MVC and MVP target the
separation of concerns across multiple components, there are some
fundamental differences between them.
</para>
<para>
For the purposes of this summary we will focus on the version of MVP
most suitable for web-based architectures.
</para>
<sect2 id="models-views-presenters">
<title>Models, Views &amp; Presenters</title>
<para>
The P in MVP stands for presenter. It’s a component which contains
the user-interface business logic for the view. Unlike MVC,
invocations from the view are delegated to the presenter, which
are decoupled from the view and instead talk to it through an
interface. This allows for all kinds of useful things such as
being able to mock views in unit tests.
</para>
<para>
The most common implementation of MVP is one which uses a Passive
View (a view which is for all intents and purposes
<quote>dumb</quote>), 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.
</para>
<para>
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.
</para>
<para>
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.
</para>
<para>
Although a common implementation of a
<ulink url="http://martinfowler.com/eaaDev/PassiveScreen.html">Passive
View</ulink> 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.
</para>
<para>
There is also a
<ulink url="http://martinfowler.com/eaaDev/SupervisingPresenter.html">Supervising
Controller</ulink> variation of MVP, which is closer to the MVC
and
<ulink url="http://en.wikipedia.org/wiki/Model_View_ViewModel">MVVM</ulink>
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.
</para>
</sect2>
</sect1>
<sect1 id="mvp-or-mvc">
<title>MVP or MVC?</title>
<para>
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.
</para>
<para>
As MVP views are defined through an interface and the interface is
technically the only point of contact between the system and the
view (other than a presenter), this pattern also allows developers
to write presentation logic without needing to wait for designers to
produce layouts and graphics for the application.
</para>
<para>
Depending on the implementation, MVP may be more easy to
automatically unit test than MVC. The reason often cited for this is
that the presenter can be used as a complete mock of the
user-interface and so it can be unit tested independent of other
components. In my experience this really depends on the languages
you are implementing MVP in (there’s quite a difference between
opting for MVP for a JavaScript project over one for say, ASP.net).
</para>
<para>
At the end of the day, the underlying concerns you may have with MVC
will likely hold true for MVP given that the differences between
them are mainly semantic. As long as you are cleanly separating
concerns into models, views and controllers (or presenters) you
should be achieving most of the same benefits regardless of the
pattern you opt for.
</para>
</sect1>
<sect1 id="mvc-mvp-and-backbone.js">
<title>MVC, MVP and Backbone.js</title>
<para>
There are very few, if any architectural JavaScript frameworks that
claim to implement the MVC or MVP patterns in their classical form
as many JavaScript developers don’t view MVC and MVP as being
mutually exclusive (we are actually more likely to see MVP strictly
implemented when looking at web frameworks such as ASP.net or GWT).
This is because it’s possible to have additional presenter/view
logic in your application and yet still consider it a flavor of MVC.
</para>
<para>
Backbone contributor <ulink url="http://ireneros.com/">Irene
Ros</ulink> subscribes to this way of thinking as when she separates
Backbone views out into their own distinct components, she needs
something to actually assemble them for her. This could either be a
controller route (such as a <literal>Backbone.Router</literal>,
covered later in the book) or a callback in response to data being
fetched.
</para>
<para>
That said, some developers do however feel that Backbone.js better
fits the description of MVP than it does MVC . Their view is that:
</para>
<itemizedlist>
<listitem>
<para>
The presenter in MVP better describes the
<literal>Backbone.View</literal> (the layer between View
templates and the data bound to it) than a controller does
</para>
</listitem>
<listitem>
<para>
The model fits <literal>Backbone.Model</literal> (it isn’t that
different from the classical MVC
<quote>Model</quote>)<literallayout></literallayout>
</para>
</listitem>
<listitem>
<para>
The views best represent templates (e.g Handlebars/Mustache
markup templates)
</para>
</listitem>
</itemizedlist>
<para>
A response to this could be that the view can also just be a View
(as per MVC) because Backbone is flexible enough to let it be used
for multiple purposes. The V in MVC and the P in MVP can both be
accomplished by <literal>Backbone.View</literal> because they’re
able to achieve two purposes: both rendering atomic components and
assembling those components rendered by other views.
</para>
<para>
We’ve also seen that in Backbone the responsibility of a controller
is shared with both the Backbone.View and Backbone.Router and in the
following example we can actually see that aspects of that are
certainly true.
</para>
<para>
Here, our Backbone <literal>PhotoView</literal> uses the Observer
pattern to <quote>subscribe</quote> to changes to a View’s model in
the line <literal>this.model.bind('change',...)</literal>. It also
handles templating in the <literal>render()</literal> method, but
unlike some other implementations, user interaction is also handled
in the View (see <literal>events</literal>).
</para>
<programlisting language="javascript">
var PhotoView = Backbone.View.extend({
//... is a list tag.
tagName: &quot;li&quot;,
// Pass the contents of the photo template through a templating
// function, cache it for a single photo
template: _.template($('#photo-template').html()),
// The DOM events specific to an item.
events: {
&quot;click img&quot; : &quot;toggleViewed&quot;
},
// The PhotoView listens for changes to its model, re-rendering. Since there's
// a one-to-one correspondence between a **Photo** and a **PhotoView** in this
// app, we set a direct reference on the model for convenience.
initialize: function() {
_.bindAll(this, 'render');
this.model.bind('change', this.render);
this.model.bind('destroy', this.remove);
},
// Re-render the photo entry
render: function() {
$(this.el).html(this.template(this.model.toJSON()));
return this;
},
// Toggle the `&quot;viewed&quot;` state of the model.
toggleViewed: function() {
this.model.viewed();
}
});
</programlisting>
<para>
Another (quite different) opinion is that Backbone more closely
resembles
<ulink url="http://martinfowler.com/eaaDev/uiArchs.html#ModelViewController">Smalltalk-80
MVC</ulink>, which we went through earlier.
</para>
<para>
As regular Backbone user Derick Bailey has
<ulink url="http://lostechies.com/derickbailey/2011/12/23/backbone-js-is-not-an-mvc-framework/">written</ulink>,
it’s ultimately best not to force Backbone to fit any specific
design patterns. Design patterns should be considered flexible
guides to how applications may be structured and in this respect,
Backbone doesn’t fit either MVC nor MVP perfectly. Instead, it
borrows some of the best concepts from multiple architectural
patterns and creates a flexible framework that just works well. Call
it <emphasis role="strong">the Backbone way</emphasis>, MV* or
whatever helps reference its flavor of application architecture.
</para>
<para>
It <emphasis>is</emphasis> however worth understanding where and why
these concepts originated, so I hope that my explanations of MVC and
MVP have been of help. Most structural JavaScript frameworks will
adopt their own take on classical patterns, either intentionally or
by accident, but the important thing is that they help us develop
applications which are organized, clean and can be easily
maintained.
</para>
</sect1>
<sect1 id="fast-facts">
<title>Fast facts</title>
<sect2 id="backbone.js">
<title>Backbone.js</title>
<itemizedlist>
<listitem>
<para>
Core components: Model, View, Collection, Router. Enforces its
own flavor of MV*
</para>
</listitem>
<listitem>
<para>
Good documentation, with more improvements on the way
</para>
</listitem>
<listitem>
<para>
Used by large companies such as SoundCloud and Foursquare to
build non-trivial applications
</para>
</listitem>
<listitem>
<para>
Event-driven communication between views and models. As we’ll
see, it’s relatively straight-forward to add event listeners
to any attribute in a model, giving developers fine-grained
control over what changes in the view
</para>
</listitem>
<listitem>
<para>
Supports data bindings through manual events or a separate
Key-value observing (KVO) library
</para>
</listitem>
<listitem>
<para>
Great support for RESTful interfaces out of the box, so models
can be easily tied to a backend
</para>
</listitem>
<listitem>
<para>
Extensive eventing system. It’s
<ulink url="http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/">trivial</ulink>
to add support for pub/sub in Backbone
</para>
</listitem>
<listitem>
<para>
Prototypes are instantiated with the <literal>new</literal>
keyword, which some developers prefer
</para>
</listitem>
<listitem>
<para>
Agnostic about templating frameworks, however Underscore’s
micro-templating is available by default. Backbone works well
with libraries like Handlebars
</para>
</listitem>
<listitem>
<para>
Doesn’t support deeply nested models, though there are
Backbone plugins such as
<ulink url="https://github.com/PaulUithol/Backbone-relational">this</ulink>
which can help<literallayout></literallayout>
</para>
</listitem>
<listitem>
<para>
Clear and flexible conventions for structuring applications.
Backbone doesn’t force usage of all of its components and can
work with only those needed.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1 id="the-basics">
<title>## <a name="thebasics">The Basics</a></title>
<sect2 id="what-is-backbone">
<title>What is Backbone?</title>
<para>
Backbone.js is one of a number of JavaScript frameworks for
creating MVC-like web applications. On the front-end, it’s my
architectural framework of choice as it’s both mature, relatively
lightweight and can be easily tested using third-party toolkits
such as Jasmine or QUnit. Other MVC frameworks you may be familiar
with include Ember.js (SproutCore 2.0), Spine, YUILibrary and
JavaScriptMVC.
</para>
<para>
Backbone is maintained by a number of contributors, most notably:
Jeremy Ashkenas, creator of CoffeeScript, Docco and Underscore.js.
As Jeremy is a believer in detailed documentation, there’s a level
of comfort in knowing you’re unlikely to run into issues which are
either not explained in the official docs or which can’t be nailed
down with some assistance from the #documentcloud IRC channel. I
strongly recommend using the latter if you find yourself getting
stuck.
</para>
</sect2>
<sect2 id="why-should-you-consider-using-it">
<title>Why should you consider using it?</title>
<para>
Backbone’s main benefits, regardless of your target platform or
device, include helping:
</para>
<itemizedlist>
<listitem>
<para>
Organize the structure to your application
</para>
</listitem>
<listitem>
<para>
Simplify server-side persistence
</para>
</listitem>
<listitem>
<para>
Decouple the DOM from your page’s data
</para>
</listitem>
<listitem>
<para>
Model data, views and routers in a succinct manner
</para>
</listitem>
<listitem>
<para>
Provide DOM, model and collection synchronization
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1 id="the-basics-1">
<title>The Basics</title>
<para>
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.
</para>
<itemizedlist>
<listitem>
<para>
Models
</para>
</listitem>
<listitem>
<para>
Collections
</para>
</listitem>
<listitem>
<para>
Routers
</para>
</listitem>
<listitem>
<para>
Views
</para>
</listitem>
<listitem>
<para>
Namespacing
</para>
</listitem>
</itemizedlist>
<sect2 id="models-1">
<title><a name="models">Models</a></title>
<para>
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.
</para>
<para>
Models can be created by extending
<literal>Backbone.Model</literal> as follows:
</para>
<programlisting language="javascript">
var Photo = Backbone.Model.extend({
defaults: {
src: 'placeholder.jpg',
title: 'an image placeholder',
coordinates: [0,0]
},
initialize: function(){
this.bind(&quot;change:src&quot;, function(){
var src = this.get(&quot;src&quot;);
console.log('Image source updated to ' + src);
});
},
changeSrc: function( source ){
this.set({ src: source });
}
});
var somePhoto = new Photo({ src: &quot;test.jpg&quot;, title:&quot;testing&quot;});
somePhoto.changeSrc(&quot;magic.jpg&quot;); // which triggers &quot;change:src&quot; and logs an update message to the console.
</programlisting>
<sect3 id="initialization">
<title>Initialization</title>
<para>
The <literal>initialize()</literal> method is called when a new
instance of a model is created. Its use is optional, however
you’ll see why it’s good practice to use it below.
</para>
<programlisting language="javascript">
var Photo = Backbone.Model.extend({
initialize: function(){
console.log('this model has been initialized');
}
});
// We can then create our own instance of a photo as follows:
var myPhoto = new Photo();
</programlisting>
</sect3>
<sect3 id="getters-setters">
<title>Getters &amp; Setters</title>
<para>
<emphasis role="strong">Model.get()</emphasis>
</para>
<para>
<literal>Model.get()</literal> provides easy access to a model’s
attributes. Attributes which are passed through to the model on
instantiation are instantly available for retrieval.
</para>
<programlisting language="javascript">
var myPhoto = new Photo({ title: &quot;My awesome photo&quot;,
src:&quot;boston.jpg&quot;,
location: &quot;Boston&quot;,
tags:['the big game', 'vacation']}),
title = myPhoto.get(&quot;title&quot;), //My awesome photo
location = myPhoto.get(&quot;location&quot;), //Boston
tags = myPhoto.get(&quot;tags&quot;), // ['the big game','vacation']
photoSrc = myPhoto.get(&quot;src&quot;); //boston.jpg
</programlisting>
<para>
Alternatively, if you wish to directly access all of the
attributes in a model’s instance directly, you can achieve this
as follows:
</para>
<programlisting language="javascript">
var myAttributes = myPhoto.attributes;
console.log(myAttributes);
</programlisting>
<para>
It is best practice to use <literal>Model.set()</literal> or
direct instantiation to set the values of a model’s attributes.
</para>
<para>
Accessing <literal>Model.attributes</literal> directly is
generally discouraged. Instead, should you need to read or clone
data, <literal>Model.toJSON()</literal> is recommended for this
purpose. If you would like to access or copy a model’s
attributes for purposes such as JSON stringification (e.g. for
serialization prior to being passed to a view), this can be
achieved using <literal>Model.toJSON()</literal>:
</para>
<programlisting language="javascript">
var myAttributes = myPhoto.toJSON();
console.log(myAttributes);
/* this returns { title: &quot;My awesome photo&quot;,
src:&quot;boston.jpg&quot;,
location: &quot;Boston&quot;,
tags:['the big game', 'vacation']}*/
</programlisting>
</sect3>
<sect3 id="model.set">
<title>Model.set()</title>
<para>
<literal>Model.set()</literal> allows us to pass attributes into
an instance of our model. Attributes can either be set during
initialization or at any time afterwards. It’s important to
avoid trying to set a Model’s attributes directly (for example
Model.caption = <quote>A new caption</quote>). Backbone uses
Model.set() to know when to broadcast that a model’s data has
changed.
</para>
<programlisting language="javascript">
var Photo = Backbone.Model.extend({
initialize: function(){
console.log('this model has been initialized');
}
});
// Setting the value of attributes via instantiation
var myPhoto = new Photo({ title: 'My awesome photo', location: 'Boston' });
var myPhoto2 = new Photo();
// Setting the value of attributes through Model.set()
myPhoto2.set({ title:'Vacation in Florida', location: 'Florida' });
</programlisting>
<para>
<emphasis role="strong">Default values</emphasis>
</para>
<para>
There are times when you want your model to have a set of
default values (e.g. in a scenario where a complete set of data
isn’t provided by the user). This can be set using a property
called <literal>defaults</literal> in your model.
</para>
<programlisting language="javascript">
var Photo = Backbone.Model.extend({
defaults:{
title: 'Another photo!',
tags: ['untagged'],
location: 'home',
src: 'placeholder.jpg'
},
initialize: function(){
}
});
var myPhoto = new Photo({ location: &quot;Boston&quot;,
tags:['the big game', 'vacation']}),
title = myPhoto.get(&quot;title&quot;), //Another photo!
location = myPhoto.get(&quot;location&quot;), //Boston
tags = myPhoto.get(&quot;tags&quot;), // ['the big game','vacation']
photoSrc = myPhoto.get(&quot;src&quot;); //placeholder.jpg
</programlisting>
<para>
<emphasis role="strong">Listening for changes to your
model</emphasis>
</para>
<para>
Any and all of the attributes in a Backbone model can have
listeners bound to them which detect when their values change.
Listeners can be added to the <literal>initialize()</literal>
function:
</para>
<programlisting language="javascript">
this.bind('change', function(){
console.log('values for this model have changed');
});
</programlisting>
<para>
In the following example, we log a message whenever a specific
attribute (the title of our Photo model) is altered.
</para>
<programlisting language="javascript">
var Photo = Backbone.Model.extend({
defaults:{
title: 'Another photo!',
tags: ['untagged'],
location: 'home',
src: 'placeholder.jpg'
},
initialize: function(){
console.log('this model has been initialized');
this.bind(&quot;change:title&quot;, function(){
var title = this.get(&quot;title&quot;);
console.log(&quot;My title has been changed to.. &quot; + title);
});
},
setTitle: function(newTitle){
this.set({ title: newTitle });
}
});
var myPhoto = new Photo({ title:&quot;Fishing at the lake&quot;, src:&quot;fishing.jpg&quot;});
myPhoto.setTitle('Fishing at sea');
//logs 'My title has been changed to.. Fishing at sea'
</programlisting>
<para>
<emphasis role="strong">Validation</emphasis>
</para>
<para>
Backbone supports model validation through
<literal>Model.validate()</literal>, which allows checking the
attribute values for a model prior to them being set.
</para>
<para>
Validation functions can be as simple or complex as necessary.
If the attributes provided are valid, nothing should be returned
from <literal>.validate()</literal>. If they are invalid, a
custom error can be returned instead.
</para>
<para>
A basic example for validation can be seen below:
</para>
<programlisting language="javascript">
var Photo = Backbone.Model.extend({
validate: function(attribs){
if(attribs.src === undefined){
return &quot;Remember to set a source for your image!&quot;;
}
},
initialize: function(){
console.log('this model has been initialized');
this.bind(&quot;error&quot;, function(model, error){
console.log(error);
});
}
});
var myPhoto = new Photo();
myPhoto.set({ title: &quot;On the beach&quot; });
//logs Remember to set a source for your image!
</programlisting>
</sect3>
</sect2>
<sect2 id="views-1">
<title><a name="views">Views</a></title>
<para>
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 <literal>render()</literal> function can be bound
to a model’s <literal>change()</literal> event, allowing the view
to always be up to date without requiring a full page refresh.
</para>
<sect3 id="creating-new-views">
<title>Creating new views</title>
<para>
Similar to the previous sections, creating a new view is
relatively straight-forward. To create a new View, simply extend
<literal>Backbone.View</literal>. I’ll explain this code in
detail below:
</para>
<programlisting language="javascript">
var PhotoSearch = Backbone.View.extend({
el: $('#results'),
render: function( event ){
var compiled_template = _.template( $(&quot;#results-template&quot;).html() );
this.el.html( compiled_template(this.model.toJSON()) );
return this; //recommended as this enables calls to be chained.
},
events: {
&quot;submit #searchForm&quot;: &quot;search&quot;,
&quot;click .reset&quot;: &quot;reset&quot;,
&quot;click .advanced&quot;: &quot;switchContext&quot;
},
search: function( event ){
//executed when a form '#searchForm' has been submitted
},
reset: function( event ){
//executed when an element with class &quot;reset&quot; has been clicked.
},
switchContext: function( event ){
//executed when an element with class &quot;advanced&quot; has been clicked.
}
});
</programlisting>
</sect3>
<sect3 id="what-is-el">
<title>What is <literal>el</literal>?</title>
<para>
<literal>el</literal> is basically a reference to a DOM element
and all views must have one. It allows for all of the contents
of a view to be inserted into the DOM at once, which makes for
faster rendering as browser performs the minimum required
reflows and repaints.
</para>
<para>
There are two ways to attach a DOM element to a view: the
element already exists in the page or a new element is created
for the view and added manually by the developer. If the element
already exists in the page, you can set <literal>el</literal> as
either a CSS selector that matches the element or a simple
reference to the DOM element.
</para>
<programlisting language="javascript">
el: '#footer',
// OR
el: document.getElementById( 'footer' )
</programlisting>
<para>
If you want to create a new element for you view, set any
combination of the following view’s properties:
<literal>tagName</literal>, <literal>id</literal> and
<literal>className</literal>. A new element will be created for
you by the framework and a reference to it will be available at
the <literal>el</literal> property.
</para>
<programlisting>
tagName: 'p', // required, but defaults to 'div' if not set
className: 'container', // optional, you can assign multiple classes to this property like so 'container homepage'
id: 'header', // optional
</programlisting>
<para>
The above code creates the <literal>DOMElement</literal> below
but doesn’t append it to the DOM.
</para>
<programlisting>
&lt;p id=&quot;header&quot; class=&quot;container&quot;&gt;&lt;/p&gt;
</programlisting>
<para>
<emphasis role="strong">Understanding
<literal>render()</literal></emphasis>
</para>
<para>
<literal>render()</literal> is an optional function that defines
the logic for rendering a template. We’ll use Underscore’s
micro-templating in these examples, but remember you can use
other templating frameworks if you prefer.
</para>
<para>
The <literal>_.template</literal> method in Underscore compiles
JavaScript templates into functions which can be evaluated for
rendering. In the above view, I’m passing the markup from a
template with id <literal>results-template</literal> to
<literal>_.template()</literal> to be compiled. Next, I set the
html of the <literal>el</literal> DOM element to the output of
processing a JSON version of the model associated with the view
through the compiled template.
</para>
<para>
Presto! This populates the template, giving you a data-complete
set of markup in just a few short lines of code.
</para>
<para>
<emphasis role="strong">The <literal>events</literal>
attribute</emphasis>
</para>
<para>
The Backbone <literal>events</literal> attribute allows us to
attach event listeners to either custom selectors, or directly
to <literal>el</literal> if no selector is provided. An event
takes the form
<literal>{&quot;eventName selector&quot;: &quot;callbackFunction&quot;}</literal>
and a number of event-types are supported, including
<literal>click</literal>, <literal>submit</literal>,
<literal>mouseover</literal>, <literal>dblclick</literal> and
more.
</para>
<para>
What isn’t instantly obvious is that under the bonnet, Backbone
uses jQuery’s <literal>.delegate()</literal> to provide instant
support for event delegation but goes a little further,
extending it so that <literal>this</literal> always refers to
the current view object. The only thing to really keep in mind
is that any string callback supplied to the events attribute
must have a corresponding function with the same name within the
scope of your view.
</para>
</sect3>
</sect2>
<sect2 id="collections">
<title><a name="collections">Collections</a></title>
<para>
Collections are sets of Models and are created by extending
<literal>Backbone.Collection</literal>.
</para>
<para>
Normally, when creating a collection you’ll also want to pass
through a property specifying the model that your collection will
contain, as well as any instance properties required.
</para>
<para>
In the following example, we create a PhotoCollection that will
contain our Photo models:
</para>
<programlisting language="javascript">
var PhotoCollection = Backbone.Collection.extend({
model: Photo
});
</programlisting>
<para>
<emphasis role="strong">Getters and Setters</emphasis>
</para>
<para>
There are a few different ways to retrieve a model from a
collection. The most straight-forward is to use
<literal>Collection.get()</literal> which accepts a single id as
follows:
</para>
<programlisting language="javascript">
var skiingEpicness = PhotoCollection.get(2);
</programlisting>
<para>
Sometimes you may also want to get a model based on its client id.
The client id is a property that Backbone automatically assigns
models that have not yet been saved. You can get a model’s client
id from its <literal>.cid</literal> property.
</para>
<programlisting language="javascript">
var mySkiingCrash = PhotoCollection.getByCid(456);
</programlisting>
<para>
Backbone Collections don’t have setters as such, but do support
adding new models via <literal>.add()</literal> and removing
models via <literal>.remove()</literal>.
</para>
<programlisting language="javascript">
var a = new Backbone.Model({ title: 'my vacation'}),
b = new Backbone.Model({ title: 'my holiday'});
var photoCollection = new PhotoCollection([a,b]);
photoCollection.remove([a,b]);
</programlisting>
<para>
<emphasis role="strong">Listening for events</emphasis>
</para>
<para>
As collections represent a group of items, we’re also able to
listen for <literal>add</literal> and <literal>remove</literal>
events for when new models are added or removed from the
collection. Here’s an example:
</para>
<programlisting language="javascript">
var PhotoCollection = new Backbone.Collection();
PhotoCollection.bind(&quot;add&quot;, function(photo) {
console.log(&quot;I liked &quot; + photo.get(&quot;title&quot;) + ' its this one, right? ' + photo.get(&quot;src&quot;));
});
PhotoCollection.add([
{title: &quot;My trip to Bali&quot;, src: &quot;bali-trip.jpg&quot;},
{title: &quot;The flight home&quot;, src: &quot;long-flight-oofta.jpg&quot;},
{title: &quot;Uploading pix&quot;, src: &quot;too-many-pics.jpg&quot;}
]);
</programlisting>
<para>
In addition, we’re able to bind a <literal>change</literal> event
to listen for changes to models in the collection.
</para>
<programlisting language="javascript">
PhotoCollection.bind(&quot;change:title&quot;, function(){
console.log('there have been updates made to this collections titles');
});
</programlisting>
<para>
<emphasis role="strong">Fetching models from the server</emphasis>
</para>
<para>
<literal>Collections.fetch()</literal> retrieves a default set of
models from the server in the form of a JSON array. When this data
returns, the current collection’s contents will be replaced with
the contents of the array.
</para>
<programlisting language="javascript">
var PhotoCollection = new Backbone.Collection;
PhotoCollection.url = '/photos';
PhotoCollection.fetch();
</programlisting>
<para>
Under the covers, <literal>Backbone.sync</literal> 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.
</para>
<para>
In the above example if we wanted to log an event when
<literal>.sync()</literal> was called, we could do this:
</para>
<programlisting language="javascript">
Backbone.sync = function(method, model) {
console.log(&quot;I've been passed &quot; + method + &quot; with &quot; + JSON.stringify(model));
};
</programlisting>
<para>
<emphasis role="strong">Resetting/Refreshing
Collections</emphasis>
</para>
<para>
Rather than adding or removing models individually, you might
occasionally wish to update an entire collection at once.
<literal>Collection.reset()</literal> allows us to replace an
entire collection with new models as follows:
</para>
<programlisting language="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;}]);
</programlisting>
</sect2>
<sect2 id="underscore-utility-functions">
<title>Underscore utility functions</title>
<para>
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
<literal>sortBy()</literal> method can be used to sort a
collection of photos based on a particular attribute.
</para>
<programlisting language="javascript">
var sortedByAlphabet = PhotoCollection.sortBy(function (photo) {
return photo.get(&quot;title&quot;).toLowerCase();
});
</programlisting>
<para>
The complete list of what Underscore can do is beyond the scope of
this guide, but can be found in its official
<ulink url="http://documentcloud.github.com/underscore/">docs</ulink>.
</para>
</sect2>
<sect2 id="routers">
<title><a name="routers">Routers</a></title>
<para>
In Backbone, routers are used to help manage application state and
for connecting URLs to application events. This is achieved using
hash-tags with URL fragments, or using the browser’s pushState and
History API. Some examples of routes may be seen below:
</para>
<programlisting language="javascript">
http://unicorns.com/#whatsup
http://unicorns.com/#search/seasonal-horns/page2
</programlisting>
<para>
Note: An application will usually have at least one route mapping
a URL route to a function that determines what happens when a user
reaches that particular route. This relationship is defined as
follows:
</para>
<programlisting language="javascript">
&quot;route&quot; : &quot;mappedFunction&quot;
</programlisting>
<para>
Let us now define our first controller by extending
<literal>Backbone.Router</literal>. For the purposes of this
guide, we’re going to continue pretending we’re creating a photo
gallery application that requires a GalleryRouter.
</para>
<para>
Note the inline comments in the code example below as they
continue the rest of the lesson on routers.
</para>
<programlisting language="javascript">
var GalleryRouter = Backbone.Router.extend({
/* define the route and function maps for this router */
routes: {
&quot;about&quot; : &quot;showAbout&quot;,
/*Sample usage: http://unicorns.com/#about*/
&quot;photos/:id&quot; : &quot;getPhoto&quot;,
/*This is an example of using a &quot;:param&quot; variable which allows us to match
any of the components between two URL slashes*/
/*Sample usage: http://unicorns.com/#photos/5*/
&quot;search/:query&quot; : &quot;searchPhotos&quot;
/*We can also define multiple routes that are bound to the same map function,
in this case searchPhotos(). Note below how we're optionally passing in a
reference to a page number if one is supplied*/
/*Sample usage: http://unicorns.com/#search/lolcats*/
&quot;search/:query/p:page&quot; : &quot;searchPhotos&quot;,
/*As we can see, URLs may contain as many &quot;:param&quot;s as we wish*/
/*Sample usage: http://unicorns.com/#search/lolcats/p1*/
&quot;photos/:id/download/*imagePath&quot; : &quot;downloadPhoto&quot;,
/*This is an example of using a *splat. splats are able to match any number of
URL components and can be combined with &quot;:param&quot;s*/
/*Sample usage: http://unicorns.com/#photos/5/download/files/lolcat-car.jpg*/
/*If you wish to use splats for anything beyond default routing, it's probably a good
idea to leave them at the end of a URL otherwise you may need to apply regular
expression parsing on your fragment*/
&quot;*other&quot; : &quot;defaultRoute&quot;
/*This is a default route that also uses a *splat. Consider the
default route a wildcard for URLs that are either not matched or where
the user has incorrectly typed in a route path manually*/
/*Sample usage: http://unicorns.com/#anything*/
},
showAbout: function(){
},
getPhoto: function(id){
/*
Note that the id matched in the above route will be passed to this function
*/
console.log(&quot;You are trying to reach photo &quot; + id);
},
searchPhotos: function(query, page){
console.log(&quot;Page number: &quot; + page + &quot; of the results for &quot; + query);
},
downloadPhoto: function(id, path){
},
defaultRoute: function(other){
console.log(&quot;Invalid. You attempted to reach:&quot; + other);
}
});
/* Now that we have a router setup, remember to instantiate it*/
var myGalleryRouter = new GalleryRouter();
</programlisting>
<para>
As of Backbone 0.5+, it’s possible to opt-in for HTML5 pushState
support via <literal>window.history.pushState</literal>. This
permits you to define routes such as
http://www.scriptjunkie.com/just/an/example. This will be
supported with automatic degradation when a user’s browser doesn’t
support pushState. For the purposes of this tutorial, we’ll use
the hashtag method.
</para>
<sect3 id="backbone.history">
<title>Backbone.history</title>
<para>
Next, we need to initialize <literal>Backbone.history</literal>
as it handles <literal>hashchange</literal> events in our
application. This will automatically handle routes that have
been defined and trigger callbacks when they’ve been accessed.
</para>
<para>
The <literal>Backbone.history.start()</literal> method will
simply tell Backbone that it’s OK to begin monitoring all
<literal>hashchange</literal> events as follows:
</para>
<programlisting language="javascript">
Backbone.history.start();
Router.navigate();
</programlisting>
<para>
As an aside, if you would like to save application state to the
URL at a particular point you can use the
<literal>.navigate()</literal> method to achieve this. It simply
updates your URL fragment without the need to trigger the
<literal>hashchange</literal> event:
</para>
<programlisting language="javascript">
/*Lets imagine we would like a specific fragment for when a user zooms into a photo*/
zoomPhoto: function(factor){
this.zoom(factor); //imagine this zooms into the image
this.navigate(&quot;zoom/&quot; + factor); //updates the fragment for us, but doesn't trigger the route
}
</programlisting>
<para>
It is also possible for <literal>Router.navigate()</literal> to
trigger the route as well as updating the URL fragment.
</para>
<programlisting language="javascript">
zoomPhoto: function(factor){
this.zoom(factor); //imagine this zooms into the image
this.navigate(&quot;zoom/&quot; + factor, true); //updates the fragment for us and triggers the route
}
</programlisting>
</sect3>
</sect2>
<sect2 id="namespacing">
<title><a name="namespacing">Namespacing</a></title>
<para>
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.
</para>
<sect3 id="what-is-namespacing">
<title>What is namespacing?</title>
<para>
The basic idea around namespacing is to avoid collisions with
other objects or variables in the global namespace. They’re
important as it’s best to safeguard your code from breaking in
the event of another script on the page using the same variable
names as you are. As a good <quote>citizen</quote> of the global
namespace, it’s also imperative that you do your best to
similarly not prevent other developer’s scripts executing due to
the same issues.
</para>
<para>
JavaScript doesn’t really have built-in support for namespaces
like other languages, however it does have closures which can be
used to achieve a similar effect.
</para>
<para>
In this section we’ll be taking a look shortly at some examples
of how you can namespace your models, views, routers and other
components specifically. The patterns we’ll be examining are:
</para>
<itemizedlist>
<listitem>
<para>
Single global variables
</para>
</listitem>
<listitem>
<para>
Object Literals
</para>
</listitem>
<listitem>
<para>
Nested namespacing
</para>
</listitem>
</itemizedlist>
<para>
<emphasis role="strong">Single global variables</emphasis>
</para>
<para>
One popular pattern for namespacing in JavaScript is opting for
a single global variable as your primary object of reference. A
skeleton implementation of this where we return an object with
functions and properties can be found below:
</para>
<programlisting language="javascript">
var myApplication = (function(){
function(){
// ...
},
return {
// ...
}
})();
</programlisting>
<para>
You’ve probably seen this technique before. A Backbone-specific
example might look like this:
</para>
<programlisting language="javascript">
var myViews = (function(){
return {
PhotoView: Backbone.View.extend({ .. }),
GalleryView: Backbone.View.extend({ .. }),
AboutView: Backbone.View.extend({ .. });
//etc.
};
})();
</programlisting>
<para>
Here we can return a set of views, but the same technique could
return an entire collection of models, views and routers
depending on how you decide to structure your application.
Although this works for certain situations, the biggest
challenge with the single global variable pattern is ensuring
that no one else has used the same global variable name as you
have in the page.
</para>
<para>
One solution to this problem, as mentioned by Peter Michaux, is
to use prefix namespacing. It’s a simple concept at heart, but
the idea is you select a common prefix name (in this example,
<literal>myApplication_</literal>) and then define any methods,
variables or other objects after the prefix.
</para>
<programlisting language="javascript">
var myApplication_photoView = Backbone.View.extend({}),
myApplication_galleryView = Backbone.View.extend({});
</programlisting>
<para>
This is effective from the perspective of trying to lower the
chances of a particular variable existing in the global scope,
but remember that a uniquely named object can have the same
effect. This aside, the biggest issue with the pattern is that
it can result in a large number of global objects once your
application starts to grow.
</para>
<para>
For more on Peter’s views about the single global variable
pattern, read his
<ulink url="http://michaux.ca/articles/javascript-namespacing">excellent
post on them</ulink>.
</para>
<para>
Note: There are several other variations on the single global
variable pattern out in the wild, however having reviewed quite
a few, I felt the prefixing approach applied best to Backbone.
</para>
<para>
<emphasis role="strong">Object Literals</emphasis>
</para>
<para>
Object Literals have the advantage of not polluting the global
namespace but assist in organizing code and parameters
logically. They’re beneficial if you wish to create easily
readable structures that can be expanded to support deep
nesting. Unlike simple global variables, Object Literals often
also take into account tests for the existence of a variable by
the same name, which helps reduce the chances of collision.
</para>
<para>
This example demonstrates two ways you can check to see if a
namespace already exists before defining it. I commonly use
Option 2.
</para>
<programlisting language="javascript">
/*Doesn't check for existence of myApplication*/
var myApplication = {};
/*
Does check for existence. If already defined, we use that instance.
Option 1: if(!myApplication) myApplication = {};
Option 2: var myApplication = myApplication || {};
We can then populate our object literal to support models, views and collections (or any data, really):
*/
var myApplication = {
models : {},
views : {
pages : {}
},
collections : {}
};
</programlisting>
<para>
One can also opt for adding properties directly to the namespace
(such as your views, in the following example):
</para>
<programlisting language="javascript">
var myGalleryViews = myGalleryViews || {};
myGalleryViews.photoView = Backbone.View.extend({});
myGalleryViews.galleryView = Backbone.View.extend({});
</programlisting>
<para>
The benefit of this pattern is that you’re able to easily
encapsulate all of your models, views, routers etc. in a way
that clearly separates them and provides a solid foundation for
extending your code.
</para>
<para>
This pattern has a number of benefits. It’s often a good idea to
decouple the default configuration for your application into a
single area that can be easily modified without the need to
search through your entire codebase just to alter it. Here’s an
example of a hypothetical object literal that stores application
configuration settings:
</para>
<programlisting language="javascript">
var myConfig = {
language: 'english',
defaults: {
enableGeolocation: true,
enableSharing: false,
maxPhotos: 20
},
theme: {
skin: 'a',
toolbars: {
index: 'ui-navigation-toolbar',
pages: 'ui-custom-toolbar'
}
}
}
</programlisting>
<para>
Note that there are really only minor syntactical differences
between the Object Literal pattern and a standard JSON data set.
If for any reason you wish to use JSON for storing your
configurations instead (e.g. for simpler storage when sending to
the back-end), feel free to.
</para>
<para>
For more on the Object Literal pattern, I recommend reading
Rebecca Murphey’s
<ulink url="http://blog.rebeccamurphey.com/2009/10/15/using-objects-to-organize-your-code">excellent
article on the topic</ulink>.
</para>
<para>
<emphasis role="strong">Nested namespacing</emphasis>
</para>
<para>
An extension of the Object Literal pattern is nested
namespacing. It’s another common pattern used that offers a
lower risk of collision due to the fact that even if a top-level
namespace already exists, it’s unlikely the same nested children
do. For example, Yahoo’s YUI uses the nested object namespacing
pattern extensively:
</para>
<programlisting language="javascript">
YAHOO.util.Dom.getElementsByClassName('test');
</programlisting>
<para>
Yahoo’s YUI uses the nested object namespacing pattern regularly
and even DocumentCloud (the creators of Backbone) use the nested
namespacing pattern in their main applications. A sample
implementation of nested namespacing with Backbone may look like
this:
</para>
<programlisting language="javascript">
var galleryApp = galleryApp || {};
// perform similar check for nested children
galleryApp.routers = galleryApp.routers || {};
galleryApp.model = galleryApp.model || {};
galleryApp.model.special = galleryApp.model.special || {};
// routers
galleryApp.routers.Workspace = Backbone.Router.extend({});
galleryApp.routers.PhotoSearch = Backbone.Router.extend({});
// models
galleryApp.model.Photo = Backbone.Model.extend({});
galleryApp.model.Comment = Backbone.Model.extend({});
// special models
galleryApp.model.special.Admin = Backbone.Model.extend({});
</programlisting>
<para>
This is readable, clearly organized, and is a relatively safe
way of namespacing your Backbone application. The only real
caveat however is that it requires your browser’s JavaScript
engine to first locate the galleryApp object, then dig down
until it gets to the function you’re calling. However,
developers such as Juriy Zaytsev (kangax) have tested and found
the performance differences between single object namespacing vs
the <quote>nested</quote> approach to be quite negligible.
</para>
<para>
<emphasis role="strong">Recommendation</emphasis>
</para>
<para>
Reviewing the namespace patterns above, the option that I prefer
when writing Backbone applications is nested object namespacing
with the object literal pattern.
</para>
<para>
Single global variables may work fine for applications that are
relatively trivial. However, larger codebases requiring both
namespaces and deep sub-namespaces require a succinct solution
that’s both readable and scalable. I feel this pattern achieves
both of these objectives and is a good choice for most Backbone
development.
</para>
</sect3>
</sect2>
<sect2 id="additional-tips">
<title><a name="additional-tips">Additional Tips</a></title>
<sect3 id="automated-backbone-scaffolding">
<title>Automated Backbone Scaffolding</title>
<para>
Scaffolding can assist in expediting how quickly you can begin a
new application by creating the basic files required for a
project automatically. If you enjoy the idea of automated MVC
scaffolding using Backbone, I’m happy to recommend checking out
a tool called
<ulink url="https://github.com/brunch/brunch">Brunch</ulink>.
</para>
<para>
It works very well with Backbone, Underscore, jQuery and
CoffeeScript and is even used by companies such as Red Bull and
Jim Beam. You may have to update any third party dependencies
(e.g. latest jQuery or Zepto) when using it, but other than that
it should be fairly stable to use right out of the box.
</para>
<para>
Brunch can be installed via the nodejs package manager and is
easy to get started with. If you happen to use Vim or Textmate
as your editor of choice, you’ll be happy to know that there are
Brunch bundles available for both.
</para>
</sect3>
<sect3 id="is-there-a-limit-to-the-number-of-routers-i-should-be-using">
<title>Is there a limit to the number of routers I should be
using?</title>
<para>
Andrew de Andrade has pointed out that DocumentCloud themselves
usually only use a single router in most of their applications.
You’re very likely to not require more than one or two routers
in your own projects as the majority of your application routing
can be kept organized in a single controller without it getting
unwieldy.
</para>
</sect3>
<sect3 id="is-backbone-too-small-for-my-applications-needs">
<title>Is Backbone too small for my application’s needs?</title>
<para>
If you find yourself unsure of whether or not your application
is too large to use Backbone, I recommend reading my post on
building large-scale jQuery &amp; JavaScript applications or
reviewing my slides on client-side MVC architecture options. In
both, I cover alternative solutions and my thoughts on the
suitability of current MVC solutions for scaled application
development.
</para>
<para>
Backbone can be used for building both trivial and complex
applications as demonstrated by the many examples Ashkenas has
been referencing in the Backbone documentation. As with any MVC
framework however, it’s important to dedicate time towards
planning out what models and views your application really
needs. Diving straight into development without doing this can
result in either spaghetti code or a large refactor later on and
it’s best to avoid this where possible.
</para>
<para>
At the end of the day, the key to building large applications is
not to build large applications in the first place. If you
however find Backbone doesn’t cut it for your requirements I
strongly recommend checking out JavaScriptMVC or SproutCore as
these both offer a little more than Backbone out of the box.
Dojo and Dojo Mobile may also be of interest as these have also
been used to build significantly complex apps by other
developers.
</para>
</sect3>
</sect2>
</sect1>
<sect1 id="restful-applications">
<title>## <a name="restfulapps">RESTful Applications</a></title>
<para>
</para>
</sect1>
<sect1 id="building-restful-applications-with-backbone">
<title><a name="restful">Building RESTful applications with
Backbone</a></title>
<para>
In this section of the book, we’re going to take a look at
developing RESTful applications using Backbone.js and modern
technology stacks. When the data for your back-end is exposed
through a purely RESTful API, tasks such as retrieving (GET),
creating (POST), updating (PUT) and deleting (DELETE) models are
made easy through Backbone’s Model API. This API is so intuitive in
fact that switching from storing records in a local data-store (e.g
localStorage) to a database/noSQL data-store is a lot simpler than
you may think.
</para>
</sect1>
<sect1 id="stack-1-building-a-backbone-app-with-node.js-express-mongoose-and-mongodb">
<title><a name="stack1">Stack 1: Building A Backbone App With Node.js,
Express, Mongoose and MongoDB</a></title>
<para>
The first stack we’ll be looking at is:
</para>
<itemizedlist>
<listitem>
<para>
<ulink url="nodejs.org">Node.js</ulink>
</para>
</listitem>
<listitem>
<para>
<ulink url="http://expressjs.com/">Express</ulink>
</para>
</listitem>
<listitem>
<para>
<ulink url="http://mongoosejs.com/">Mongoose</ulink>
</para>
</listitem>
<listitem>
<para>
and <ulink url="http://www.mongodb.org/">MongoDB</ulink>
</para>
</listitem>
</itemizedlist>
<para>
with <ulink url="http://jade-lang.com/">Jade</ulink> used optionally
as a view/templating engine.
</para>
<sect2 id="reviewing-the-stack">
<title>Reviewing the stack</title>
<para>
As you may know, node.js is an event-driven platform (built on the
<ulink url="http://code.google.com/apis/v8/design.html">V8</ulink>
runtime), designed for writing fast, scalable network
applications. It’s reasonably lightweight, efficient and great for
real-time applications that are data-intensive.
</para>
<para>
Express is a small web-development framework written with node.js,
based on <ulink url="http://www.sinatrarb.com/">Sinatra</ulink>.
It supports a number of useful features such as intuitive views,
robust routing and a focus on high performance.
</para>
<para>
Next on the list are MongoDB and Mongoose. MongoDB is an
open-source, document-oriented database store designed with
scalability and agility in mind. As a
<ulink url="http://en.wikipedia.org/wiki/NoSQL">noSQL</ulink>
database, rather than storing data in tables and rows (something
we’re very used to doing with relational databases), with MongoDB
we instead store JSON-like documents using dynamic schemas. One of
the goals of Mongo is to try bridging the gap between key-value
stores (speed, scalability) and
<ulink url="http://en.wikipedia.org/wiki/Relational_database">relational</ulink>
databases (rich functionality).
</para>
<para>
Mongoose is a JavaScript library that simplifies how we interact
with Mongo. Like Express, it’s designed to work within the node.js
environment and tries to solve some of the complexities with
asynchronous data storage by offering a more user-friendly API. It
also adds chaining features into the mix, allowing for a slightly
more expressive way of dealing with our data.
</para>
<para>
Jade is a template engine influenced by Haml (which we’ll be
looking at later). It’s implemented with JavaScript (and also runs
under node). In addition to supporting Express out of the box, it
boasts a number of useful features including support for mixins,
includes, caching, template inheritance and much more. Whilst
abstractions like Jade certainly aren’t for everyone, our
practical will cover working both with and without it.
</para>
</sect2>
<sect2 id="practical">
<title>Practical</title>
<para>
For this practical, we’re going to once again look at extending
the popular Backbone Todo application. Rather than relying on
localStorage for data persistence, we’re going to switch to
storing Todos in a MongoDB document-store instead. The code for
this practical can be found in
<literal>practicals\stacks\option2</literal>
</para>
<para>
<emphasis role="strong">app.js</emphasis>
</para>
<para>
(See
<ulink url="https://github.com/addyosmani/backbone-boilerplates/blob/master/option2/app.js">here</ulink>
for the source)
</para>
<para>
We must first include the node dependencies required by our
application. These are Express, Mongoose and Path (a module
containing utilities for dealing with file paths.
</para>
<programlisting language="javascript">
var application_root = __dirname,
express = require(&quot;express&quot;),
path = require(&quot;path&quot;),
mongoose = require('mongoose');
</programlisting>
<para>
Next, create a new Express server.
<literal>express.createServer()</literal> is a simple way of
creating an instance of express.HTTPServer, which we’ll be using
to pass in our routes.
</para>
<programlisting language="javascript">
var app = express.createServer();
</programlisting>
<para>
After this, connect Mongoose up to a database (in our case,
localhost should suffice). Should you require the ability to pass
in authentication information, here’s a sample containing all of
the supported URL parameters:
<literal>mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]</literal>
</para>
<programlisting language="javascript">
mongoose.connect('mongodb://localhost/my_database');
</programlisting>
<para>
A Mongoose model for any Todo item can now be easily defined by
passing a schema instance to <literal>mongoose.model</literal>. In
our case the schema covers a Todo item’s <literal>text</literal>
content, its <literal>done</literal> state and
<literal>order</literal> position in the overall Todo list.
</para>
<programlisting language="javascript">
var Todo = mongoose.model('Todo', new mongoose.Schema({
text: String,
done: Boolean,
order: Number
}));
</programlisting>
<para>
The <literal>configure()</literal> methods allows us to setup what
we need for the current environment with our Express server. Note
that lower down in the configuration are two view/view related
lines. The last one explicitly sets the viewing/templating engine
to be used as Jade
<literal>app.set('view engine', 'jade')</literal>. We can avoid
these if we wish to use plain HTML/JS for our templates instead.
</para>
<programlisting language="javascript">
app.configure(function(){
// the bodyParser middleware parses JSON request bodies
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(application_root, &quot;public&quot;)));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
app.set('views', path.join(application_root, &quot;views&quot;));
app.set('view engine', 'jade')
});
</programlisting>
<para>
Should you prefer to switch out Jade for an alternative view
engine, this can be done fairly trivially. See the section under
<quote>Templating</quote> here:
https://github.com/joyent/node/wiki/modules. For example, to
switch to EJS, you would simply write
<literal>app.set('view engine', 'ejs')</literal>
</para>
<para>
Express makes use of common HTTP verbs (get, put, post etc.) to
provide easy to use, expressive routing API based on CRUD (Create,
Read, Update and Delete). Below for example, we can define what
happens when the browser requests the root <quote>/</quote>. As a
trivial route in this application, it doesn’t do anything
particularly exciting, however getters typically read or retrieve
data.
</para>
<programlisting language="javascript">
app.get('/', function(req, res){
res.send('Hello World');
});
</programlisting>
<para>
Onto something a little more useful and in our next route,
navigating to <quote>/todo</quote> will actually render our Jade
view <quote>todo.jade</quote>, as seen in the callback. Additional
configuration values can be passed as the second parameter, such
as the custom title specified below.
</para>
<programlisting language="javascript">
app.get('/todo', function(req, res){
res.render('todo', {title: &quot;Our sample application&quot;});
});
</programlisting>
<para>
Next, we can see the first of our <quote>/api/</quote> routes.
</para>
<programlisting language="javascript">
app.get('/api/todos', function(req, res){
return Todo.find(function(err, todos) {
return res.send(todos);
});
});
</programlisting>
<para>
The callback to our next route supports querying for todos based
on a specific ID. The route string itself (once compiled) will be
converted from <quote>/api/todos/:id</quote> to a regular
expression. As you might have guessed, this is a hint that routes
can also be regular expression literals if we wished to do
something more complex.
</para>
<programlisting language="javascript">
app.get('/api/todos/:id', function(req, res){
return Todo.findById(req.params.id, function(err, todo) {
if (!err) {
return res.send(todo);
}
});
});
</programlisting>
<para>
Similarly, we want to support updating todos based on a specific
ID as well. The following allows us to query a todo by ID and then
update the values of it’s three attributes (text, done, order)
easily.
</para>
<programlisting language="javascript">
app.put('/api/todos/:id', function(req, res){
return Todo.findById(req.params.id, function(err, todo) {
todo.text = req.body.text;
todo.done = req.body.done;
todo.order = req.body.order;
return todo.save(function(err) {
if (!err) {
console.log(&quot;updated&quot;);
}
return res.send(todo);
});
});
});
</programlisting>
<para>
We’ve so far covered requesting todos and updating them, but a
core part of the application requires us to insert (or add) new
todos to our data-store. Below we can create new <code>Todo</code>
models and simply save them.
</para>
<programlisting language="javascript">
app.post('/api/todos', function(req, res){
var todo;
todo = new Todo({
text: req.body.text,
done: req.body.done,
order: req.body.order
});
todo.save(function(err) {
if (!err) {
return console.log(&quot;created&quot;);
}
});
return res.send(todo);
});
</programlisting>
<para>
We of course also want to support deleting todos (e.g if a todo
has been <quote>cleared</quote>, it should be deleted). This also
works based on a specific todo ID.
</para>
<programlisting language="javascript">
app.delete('/api/todos/:id', function(req, res){
return Todo.findById(req.params.id, function(err, todo) {
return todo.remove(function(err) {
if (!err) {
console.log(&quot;removed&quot;);
return res.send('')
}
});
});
});
</programlisting>
<para>
Finally, this last line is to ensure we’re only listening on the
port app.js is running.
</para>
<programlisting language="javascript">
app.listen(3000);
</programlisting>
<para>
<emphasis role="strong">script.js - updating our Backbone.js
app</emphasis>
</para>
<para>
In the <literal>/public/js</literal> folder of options 1 (HTML
templates) and 2 (Jade) for the practical, you’ll find a version
of the Backbone Todo app originally by Jerome Gravel-Niquet. Let’s
pay attention to
<ulink url="https://github.com/addyosmani/backbone-boilerplates/blob/master/option2/public/js/script.js">script.js</ulink>.
In order to change the application to work with our new back-end,
we’ll need to make some very minor changes to this.
</para>
<para>
Reviewing <literal>window.TodoList</literal> (a Backbone
Collection), you’ll notice that it has a property called
<literal>localStorage</literal>, which uses the Backbone
<ulink url="https://github.com/jeromegn/Backbone.localStorage">localStorage</ulink>
adapter in order to facilitate storing data using the browser’s
localStorage features.
</para>
<programlisting language="javascript">
window.TodoList = Backbone.Collection.extend({
// Reference to this collection's model.
model: Todo,
// Save all of the todo items under the `&quot;todos&quot;` namespace.
// Typically, this should be a unique name within your application
localStorage: new Store(&quot;todos&quot;),
</programlisting>
<para>
In order to switch it over to our RESTful backend, we’re going to
make use of the <literal>url</literal> property or function on a
collection to reference its location on the server. Models inside
of a collection then use <literal>url</literal> to construct URLs
of their own. As all of the CRUD for our RESTful API works on the
base route <quote>/api/todos</quote>, this is the value we set
<literal>url</literal> to.
</para>
<programlisting language="javascript">
// localStorage: new Store(&quot;todos&quot;),
url: '/api/todos',
</programlisting>
<para>
This is the only change necessary to our existing Backbone
application in order to get things working. Pretty easy, right?
</para>
<para>
<emphasis role="strong">todo.jade</emphasis>
</para>
<para>
The Jade templates for our application cover declarative markup
for both the index (layout.jade) of the application and the main
Todo container (todo.jade). It also covers the script-tag
templates used for rendering each new Todo item that’s added.
</para>
<programlisting language="html">
// Todo App Interface
#todoapp
.title
h1 Todos
.content
#create-todo
input#new-todo(placeholder=&amp;quot;What needs to be done?&amp;quot;, type=&amp;quot;text&amp;quot;)
span.ui-tooltip-top(style=&amp;quot;display:none;&amp;quot;) Press Enter to save this task
#todos
ul#todo-list
#todo-stats
// Templates
script#item-template(type=&amp;quot;text/template&amp;quot;)
&amp;lt;div class=&amp;quot;todo &amp;lt;%= done ? 'done' : '' %&amp;gt;&amp;quot;&amp;gt;
.display
&amp;lt;input class=&amp;quot;check&amp;quot; type=&amp;quot;checkbox&amp;quot; &amp;lt;%= done ? 'checked=&amp;quot;checked&amp;quot;' : '' %&amp;gt; /&amp;gt;
.todo-text
span#todo-destroy
.edit
input.todo-input(type=&amp;quot;text&amp;quot;, &amp;quot;value&amp;quot;=&amp;quot;&amp;quot;)
&amp;lt;/div&amp;gt;
script#stats-template(type=&amp;quot;text/template&amp;quot;)
&amp;lt;% if (total) { %&amp;gt;
span.todo-count
span.number &amp;lt;%= remaining %&amp;gt;
span.word &amp;lt;%= remaining == 1 ? 'item' : 'items' %&amp;gt;
| left.
&amp;lt;% } %&amp;gt;
&amp;lt;% if (done) { %&amp;gt;
span.todo-clear
a(href=&amp;quot;#&amp;quot;)
| Clear
span.number-done &amp;lt;%= done %&amp;gt;
| completed
span.word-done &amp;lt;%= done == 1 ? 'item' : 'items' %&amp;gt;
&amp;lt;% } %&amp;gt;
</programlisting>
<para>
<emphasis role="strong">layout.jade</emphasis>
</para>
<programlisting language="html">
!!! 5
//if lt IE 6
&amp;lt;html class=&amp;quot;no-js ie6 oldie&amp;quot; lang=&amp;quot;en&amp;quot;&amp;gt;
//if IE 7
&amp;lt;html class=&amp;quot;no-js ie7 oldie&amp;quot; lang=&amp;quot;en&amp;quot;&amp;gt;
//if IE 8
&amp;lt;html class=&amp;quot;no-js ie8 oldie&amp;quot; lang=&amp;quot;en&amp;quot;&amp;gt;
//if gt IE 8
&amp;lt;!--&amp;gt; &amp;lt;html class=&amp;quot;no-js&amp;quot; lang=&amp;quot;en&amp;quot;&amp;gt; &amp;lt;!--
head
meta(charset=&amp;quot;utf-8&amp;quot;)
meta(http-equiv=&amp;quot;X-UA-Compatible&amp;quot;, content=&amp;quot;IE=edge,chrome=1&amp;quot;)
title=title
meta(name=&amp;quot;description&amp;quot;, content=&amp;quot;&amp;quot;)
meta(name=&amp;quot;author&amp;quot;, content=&amp;quot;&amp;quot;)
meta(name=&amp;quot;viewport&amp;quot;, content=&amp;quot;width=device-width,initial-scale=1&amp;quot;)
// CSS concatenated and minified via ant build script
link(rel=&amp;quot;stylesheet&amp;quot;, href=&amp;quot;css/style.css&amp;quot;)
// end CSS
script(src=&amp;quot;js/libs/modernizr-2.0.6.min.js&amp;quot;)
body
#container
header
#main(role=&amp;quot;main&amp;quot;)!=body
footer
//! end of #container
script(src=&amp;quot;//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js&amp;quot;)
script
window.jQuery || document.write('&amp;lt;script src=&amp;quot;js/libs/jquery-1.6.2.min.js&amp;quot;&amp;gt;&amp;lt;\\/script&amp;gt;')
// scripts concatenated and minified via ant build script
script(src=&amp;quot;js/mylibs/underscore.js&amp;quot;)
script(src=&amp;quot;js/mylibs/backbone.js&amp;quot;)
script(defer, src=&amp;quot;js/plugins.js&amp;quot;)
script(defer, src=&amp;quot;js/script.js&amp;quot;)
// end scripts
// Change UA-XXXXX-X to be your site's ID
script
window._gaq = [['_setAccount','UAXXXXXXXX1'],['_trackPageview'],['_trackPageLoadTime']];
Modernizr.load({load: ('https:' == location.protocol ? '//ssl' : '//www') + '.google-analytics.com/ga.js'});
//if lt IE 7
script(src=&amp;quot;//ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js&amp;quot;)
script
window.attachEvent('onload',function(){CFInstall.check({mode:'overlay'})})
&amp;lt;/html&amp;gt;
</programlisting>
<para>
<emphasis role="strong">static.html</emphasis>
</para>
<para>
Alternatively, a static version of our index which doesn’t rely on
Jade can be put together as follows. See
<ulink url="https://github.com/addyosmani/backbone-boilerplates/blob/master/option1/public/static.html">here</ulink>
for the complete file or below for a sample.
</para>
<programlisting language="html">
&amp;lt;div id=&amp;quot;container&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;main&amp;quot; role=&amp;quot;main&amp;quot;&amp;gt;
&amp;lt;!-- Todo App Interface--&amp;gt;
&amp;lt;div id=&amp;quot;todoapp&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;
&amp;lt;h1&amp;gt;Todos&amp;lt;/h1&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;create-todo&amp;quot;&amp;gt;
&amp;lt;input id=&amp;quot;new-todo&amp;quot; placeholder=&amp;quot;What needs to be done?&amp;quot; type=
&amp;quot;text&amp;quot; /&amp;gt;&amp;lt;span style=&amp;quot;display:none;&amp;quot; class=&amp;quot;ui-tooltip-top&amp;quot;&amp;gt;Press Enter to
save this task&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;todos&amp;quot;&amp;gt;
&amp;lt;ul id=&amp;quot;todo-list&amp;quot;&amp;gt;&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;todo-stats&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;!-- Templates--&amp;gt;
&amp;lt;script id=&amp;quot;item-template&amp;quot; type=&amp;quot;text/template&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;todo &amp;lt;%= done ? 'done' : '' %&amp;gt;&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;display&amp;quot;&amp;gt;&amp;lt;input class=&amp;quot;check&amp;quot; type=&amp;quot;checkbox&amp;quot; &amp;lt;%= done ? 'checked=&amp;quot;checked&amp;quot;' : '' %&amp;gt; /&amp;gt;
&amp;lt;div class=&amp;quot;todo-text&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;span id=&amp;quot;todo-destroy&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div class=&amp;quot;edit&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; value=&amp;quot;&amp;quot; class=&amp;quot;todo-input&amp;quot;/&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;script id=&amp;quot;stats-template&amp;quot; type=&amp;quot;text/template&amp;quot;&amp;gt;
&amp;lt;% if (total) { %&amp;gt;
&amp;lt;span class=&amp;quot;todo-count&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;number&amp;quot;&amp;gt;&amp;lt;%= remaining %&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;word&amp;quot;&amp;gt;&amp;lt;%= remaining == 1 ? 'item' : 'items' %&amp;gt;&amp;lt;/span&amp;gt; left.
&amp;lt;/span&amp;gt;&amp;lt;% } %&amp;gt;
&amp;lt;% if (done) { %&amp;gt;
&amp;lt;span class=&amp;quot;todo-clear&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt; Clear
&amp;lt;span class=&amp;quot;number-done&amp;quot;&amp;gt;&amp;lt;%= done %&amp;gt;&amp;lt;/span&amp;gt; completed
&amp;lt;span class=&amp;quot;word-done&amp;quot;&amp;gt;&amp;lt;%= done == 1 ? 'item' : 'items' %&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;% } %&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;!--! end of #container--&amp;gt;
</programlisting>
</sect2>
<sect2 id="practical-setup">
<title>Practical Setup</title>
<para>
We’ve now gone through the major points of developing a RESTful
backend using Node.js, Express and Mongoose. Next, let’s make sure
you can get your environment setup to run the updated Todo app.
</para>
<sect3 id="mongodb">
<title>MongoDB</title>
<para>
Once you’ve downloaded
<ulink url="http://www.mongodb.org/downloads">MongoDB</ulink>,
you’ll need to complete two steps to get it up and running.
</para>
<para>
<emphasis role="strong">Data directories</emphasis>
</para>
<para>
MongoDB stores data in the bin/data/db folder but won’t actually
create this directory for you. Navigate to where you’ve
downloaded and extracted MongoDB and run the following from
terminal:
</para>
<programlisting language="html">
sudo mkdir -p /data/db/
sudo chown `id -u` /data/db
</programlisting>
<para>
<emphasis role="strong">Running and connecting to your
server</emphasis>
</para>
<para>
Once this is done, open up two terminal windows.
</para>
<para>
In the first, <literal>cd</literal> to your MongoDB bin
directory or type in the complete path to it. You’ll need to
start <cpde>mongod`.
</para>
<programlisting language="html">
$ ./bin/mongod
</programlisting>
<para>
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
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
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>
</para>
</sect3>
</sect2>
</sect1>
<sect1 id="introduction-1">
<title>Introduction</title>
<para>
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 <ulink url="http://www.sinatrarb.com/">Sinatra</ulink> - a
DSL (domain specific language) for rapidly creating web applications
in Ruby. Similar to the
<ulink url="https://github.com/addyosmani/backbone-fundamentals/#stack1">section</ulink>
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.
</para>
</sect1>
<sect1 id="what-is-sinatra">
<title>What Is Sinatra?</title>
<para>
In the past, you’ve likely come across or used
<ulink url="http://rubyonrails.org">Ruby on Rails</ulink> (RoR) - a
popular web application framework for the Ruby programming language
that helps organize applications using the MVC pattern. Sinatra is a
much smaller, more light-weight alternative to it.
</para>
<para>
Whilst a very basic Rails application may require a more strict
project structure (such as requiring the use of controllers, views
and routing etc.), Sinatra doesn’t require as many of these
dependencies, sacrificing the helpers needed to connect to
databases, tools to create forms or any of the other utilities Rails
comes with out of the box.
</para>
<para>
What Sinatra does have is a
<emphasis role="strong">minimal</emphasis> set of features most
useful for tying specific URLs and RESTful HTTP actions to blocks of
Ruby code and returning this code’s output as a response. Sinatra is
particularly useful for getting projects up and running quickly
where we don’t have a need for the extra pieces RoR provides.
</para>
<para>
For those who are familiar with more Rails, you probably know that
it requires a separate routes file to define how an application
should be responding to requests. These are then piped into the
relevant models and controllers as needed.
</para>
<para>
Sinatra takes a more straight-forward approach, providing us with
the most simple path to handling routing. By declaring
<literal>get</literal>,<literal>post</literal>,
<literal>put</literal> or <literal>delete</literal> actions, we can
inform Sinatra to add a new route, which we can then have respond to
requests.
</para>
<para>
The framework is particularly useful for writing APIs, widgets and
small-scale applications that can power the backend of a
client-heavy application. As mentioned, we will be using it to power
our API.
</para>
</sect1>
<sect1 id="getting-started-with-sinatra">
<title>Getting Started With Sinatra</title>
<para>
Let’s review how to write and run a very basic Sinatra application.
As most programming languages and frameworks typically start with
some variation of <quote>Hello World</quote>, we’ll start with a
similar example.
</para>
<para>
Note: Before beginning this section, I recommend installing Sinatra
on your system. A guide to doing this can be found in the
<link linkend="preq">prerequisites</link> section lower down in the
article.
</para>
<sect2 id="routes">
<title>Routes</title>
<para>
As mentioned, Sinatra allows us to define new routes using HTTP
actions. Semantically, a route follows quite a simple structure:
</para>
<programlisting language="ruby">
&lt;a HTTP action&gt; &lt;the desired route&gt; do
# some behaviour
end
</programlisting>
<para>
A tiny route that outputs a <quote>Hello World</quote>-like
message when we attempt to <quote>get</quote> the root could thus
be written as follows:
</para>
<programlisting language="ruby">
require 'sinatra'
get '/' do
&quot;Hello World! Is it me you're looking for?&quot;
end
</programlisting>
<para>
To run this snippet, we can can simply save it to a local ’.rb’
file and execute it as follows:
</para>
<programlisting language="ruby">
ruby -rubygems example.rb
</programlisting>
<para>
If we now navigated to http://localhost:4567 in our browser we
could now see the application running successfully.
</para>
<para>
The HTTP verbs we commonly work with when writing RESTful web
services are: <literal>get</literal>, <literal>post</literal>,
<literal>delete</literal> and <literal>put</literal>. As we now
know, all Sinatra routes are basically HTTP actions
(`<literal>get</literal> etc.) that are paired with a URL-matching
pattern. We associate a pair of an action and route with code we
would like sent back to the browser (executed)if the route is
reached. Sinatra doesn’t enforce much in the way of architectural
structure, instead relying on simplicity to supporting writing
powerful APIs.
</para>
<para>
Here’s an example of a skeleton service we could put together
supporting four common HTTP actions: ruby ``` get
<quote>/items</quote> do # list all items available end
</para>
<para>
get <quote>/item/:id</quote> do # get a single item end
</para>
<para>
post <quote>/item</quote> do # create a new item end
</para>
<para>
put <quote>/item/:id</quote> do # update an existing item end
</para>
<para>
delete <quote>/item/:id</quote> do # delete an item end ```
</para>
<para>
Sinatra’s routing is both easy for beginners to get started with
but is also flexible enough for those wishing to define more
complex routes. As you probably noticed in the above example,
routes can include named parameters (e.g
<literal>/item/:id</literal>). We can actually access the content
of these routes using the <literal>params</literal> hash as
follows:
</para>
<programlisting language="ruby">
get '/item/:id' do
# this matches &quot;GET /item/10&quot; and &quot;GET /item/11&quot;
# params[:id] is &quot;10&quot; or &quot;11&quot;
&quot;You reached #{params[:id]}&quot;
end
</programlisting>
<para>
Sinatra also supports route matching via splats, wildcards and
regular expressions. For more information on this I recommend
reading the official
<ulink url="http://www.sinatrarb.com/documentation">docs</ulink>.
Let’s now take a look at handlers.
</para>
<para>
Sinatra includes convenient handler methods for tasks such as
redirection, halting and passing.
</para>
<sect3 id="redirection">
<title>Redirection</title>
<para>
A simple route supporting redirection which returns a 302
response can be written as follows:
</para>
<programlisting language="ruby">
get '/items' do
redirect '/items/welcome'
end
</programlisting>
<para>
And if we wish to pass additional parameters such as arguments
we can do so like this: redirect
<quote>http://site.com/</quote>, <quote>Oops! I think we have a
problem!</quote>
</para>
</sect3>
<sect3 id="halting">
<title>Halting</title>
<para>
To immediately stop a request (halting) we can use
<quote>halt</quote>. Heres an example of halting a request where
we specify the message body:
</para>
<para>
<literal>halt &quot;who goes there!?&quot;</literal>
</para>
</sect3>
<sect3 id="passing">
<title>Passing</title>
<para>
<quote>Passing</quote> is the concept of deferring processing of
a block to the next matching route. We do this using
<literal>pass</literal>. In the following example if a parameter
isnt the username we expect (rick-astley) we simply pass it on:
</para>
<programlisting language="ruby">
get '/members/:username' do
pass unless params[:username] == 'rick-astley'
'Never gonna give you up, never gonna let you down'
end
get '/member/*' do
'Welcome!'
end
</programlisting>
<para>
There are also handler methods that can assist with sessions
(specifically, cookie-based session handling). To use Sinatra’s
session handling, first enable it in your application with:
</para>
<programlisting language="ruby">
enable :sessions
</programlisting>
<para>
You can then use the session handling capabilities as follows:
</para>
<programlisting language="ruby">
get '/items' do
session['visitCounter'] ||= 0;
session['visitCounter'] += 1;
&quot;This page has been accessed #{session['visitCounter']} times&quot;
end
</programlisting>
<para>
Note: By default enable:sessions will store all data in cookies.
If this is not desired, you can not call this and instead use
some Rack middleware instead. For more on this see
<ulink url="http://www.sinatrarb.com/intro#Using%20Sessions">here</ulink>.
</para>
<para>
This only touches the surface of what can be done using routes
and handlers, but is sufficient for us to write the
Sinatra-powered API service we require in the practical section
of this chapter.
</para>
</sect3>
</sect2>
</sect1>
<sect1 id="templating-and-haml">
<title>Templating And HAML</title>
<para>
Let’s now discuss templating.Out of the box, we can begin using
templates in our Sinatra applications with ERB. ERB is included with
Ruby and allows Ruby code to be added to any plain text document for
the purpose of generating information or flow control. In the
following example using an ERB template, note that views are by
default located in the <literal>views</literal> directory of our
application.
</para>
<programlisting language="ruby">
get '/items' do
erb :default
# renders views/default.erb
end
</programlisting>
<para>
A useful Sinatra convention worth noting is how layouts are handled.
Layouts automatically search for a views/layout template which is
rendered before any other views are loaded. With ERB, our
views/layout.erb file could look as follows:
</para>
<programlisting language="html">
&lt;html&gt;
&lt;head&gt;&lt;/head&gt;
&lt;body&gt;
&lt;%= data %&gt;
&lt;/body&gt;
&lt;/html&gt;
</programlisting>
<para>
Haml is a popular alternative to ERB which offers an abstract syntax
for writing application templates. It has been said to be:
</para>
<itemizedlist>
<listitem>
<para>
Straight-forward to learn
</para>
</listitem>
<listitem>
<para>
Very easy to read and use for visually expressing a hierarchy of
DOM elements
</para>
</listitem>
<listitem>
<para>
Popular with web designers as it builds on top of CSS syntax
</para>
</listitem>
<listitem>
<para>
Well documented with a large community backing it
</para>
</listitem>
<listitem>
<para>
Almost as fast as ERB
</para>
</listitem>
</itemizedlist>
<para>
For the purpose of comparison, below we can see an ERB template
compared to it’s Haml equivalent.
</para>
<sect2 id="erb">
<title>ERB</title>
<programlisting language="html">
&lt;div class=&quot;todo&quot; id=&quot;content&quot;&gt;
&lt;h2 class=&quot;entry_title&quot;&gt;&lt;%= h @todo.title %&gt;&lt;/h2&gt;
&lt;div class=&quot;entry_link&quot;&gt;&lt;%= link_to('link', @todo.link) %&gt;&lt;/div&gt;
&lt;/div&gt;
</programlisting>
</sect2>
<sect2 id="haml">
<title>Haml</title>
<programlisting language="html">
.todo#content
%h2.entry_title= @todo.title
.entry_link= link_to('link', @todo.link)
</programlisting>
<para>
One of the first things we notice is that the Haml snippet looks
significantly more like CSS than it does traditional markup. It’s
much easier to read and we no longer need to be concerned with
divs, spans, closing tags or other semantic rules that usually
mean more keystrokes. The approach taken to making whitespace a
part of the syntax also means it can be much easier to compare
changes between multiple documents (especially if you’re doing a
diff).
</para>
<para>
In the list of Haml features, we briefly mentioned web designers.
As developers, we regularly need to communicate and work with
designers, but we always have to remember that at the end of the
day, they are not programmers. They’re usually more concerned with
the look and the feel of an application, but if we want them to
write mark-up as a part of the templates or skins they create,
Haml is a simpler option that has worked well for teams at a
number of companies.
</para>
<programlisting language="ruby">
%h1 This is some h1 text
%h2 This is some h2 text.
%p Now we have a line containing a single instance variable: @content
%p= @content
%p Embedding Ruby code in the middle of a line can be done using ==.
%p== Here is an example: #{@foobar}
%p We can also add attributes using {}
%p{:style =&gt; &quot;color:green&quot;} We just made this paragraph green!
%p You'll want to apply classes and ids to your DOM, too.
%p.foo This has the foo class
%p.bar This has the bar class
%p#foobar This has the foobar id
%p.foo#foobar Or you can combine them!
%p Nesting can be done like this
%p
Or even like this
</programlisting>
<para>
Note: Haml is whitespace sensitive and will not correctly work if
it isn’t indented by an even number of spaces. This is due to
whitespace being used for nesting in place of the classic HTML
markup approach of closing tags.
</para>
</sect2>
</sect1>
<sect1 id="mongodb-ruby-driver">
<title>MongoDB Ruby Driver</title>
<sect2 id="getting-started">
<title>Getting started</title>
<para>
Once the MongoDB Ruby driver is installed, we can begin to use it
to connect to a Mongo database. To create a connection using
localhost, we simply specify the driver as a dependency. Assuming
we’re using the default port we can then connect as follows:
</para>
<programlisting language="ruby">
require 'mongo'
# where 'learning-mongo' is the name of our database:
db = Connection.new.db('learning-mongo');
</programlisting>
<para>
We probably also want to place some data into
<quote>learning-mongo</quote>. It could be as simple as a note, so
why don’t we go ahead and begin a notes collection?:
</para>
<para>
<literal>ruby notes = db.collection('notes')</literal> Something
interesting worth noting is that at this point, we haven’t
actually created the database nor the collection we’re referencing
above.
</para>
<para>
Neither of these items exist in Mongo (just yet) but as we’re
working with a new database but they will once we insert some real
data.
</para>
<para>
A new note could be defined using key/value pairs as follows and
then inserted into <quote>learning-mongo</quote> using
<literal>collection.insert()</literal>:
</para>
<programlisting language="ruby">
our_note = { :text =&gt; 'Remember the milk', :remindInterval =&gt; 'weekly'}
note_id = notes.insert(our_note)
</programlisting>
<para>
What is returned from inserting a note into the notes collection
is an <literal>ObjectId</literal> reference for the note from
Mongo. This is useful as we can re-use it to locate the same
document in our database.
</para>
<programlisting language="ruby">
note = notes.find( :id =&gt; note_id ).first
</programlisting>
<para>
This can also be used in conjunction with Mongo’s
<literal>collection.update()</literal> method and
<ulink url="http://www.mongodb.org/display/DOCS/Updating">query</ulink>
operators (i.e <literal>$set</literal>) to replace fields in an
existing document.
</para>
<para>
We might update an entire document as follows:
</para>
<programlisting language="ruby">
note = notes.find( :id =&gt; note_id ).first
note[:text] = 'Remember the bread'
notes.update({ :_id =&gt; note_id }, note)
</programlisting>
<para>
or using <literal>$set</literal>, update an existing document
without overwriting the entire object as like this:
</para>
<programlisting language="ruby">
notes.update({ :_id =&gt; note_id }, '$set' =&gt; { :text = &gt; 'Remember the bread' })
</programlisting>
<para>
Useful to know: Almost each MongoDB document has an _id field as
it’s first attribute. This can normally be of any type, however a
special BSON datatype is provided for object ids. It’s a 12-byte
binary value that has a high probability of being unique when
allocated.
</para>
<para>
Note: Whilst we opted for the MongoDB Ruby Driver for this stack,
you may also be interested in
<emphasis role="strong">DataMapper</emphasis> - 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
<ulink url="http://datamapper.org/why.html">project page</ulink>.
<ulink url="http://sinatra-book.gittr.com/#datamapper">Sinatra:
The Book</ulink> also contains a brief tutorial on DataMapper for
anyone interested in exploring it further.
</para>
</sect2>
</sect1>
<sect1 id="practical-1">
<title>Practical</title>
<para>
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.
</para>
<para>
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.
</para>
<sect2 id="installing-the-prerequisites">
<title><a id="preq">Installing The Prerequisites</a></title>
<sect3 id="ruby">
<title>Ruby</title>
<para>
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:
</para>
<para>
<literal>$ ruby -v</literal>
</para>
<para>
The output of this will either be the version of Ruby installed
or an error complaining that Ruby wasn’t found.
</para>
<para>
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.
</para>
</sect3>
<sect3 id="ruby-gems">
<title>Ruby Gems</title>
<para>
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.
</para>
<para>
On OSX, Linux or Windows go to
<ulink url="http://rubyforge.org/projects/rubygems">http://rubyforge.org/projects/rubygems</ulink>
and download the latest version of Ruby Gems. Once downloaded,
open up a terminal, navigate to the folder where this resides
and enter:
</para>
<programlisting>
$&gt; tar xzvf rubygems.tgz
$&gt; cd rubygems
$&gt; sudo ruby setup.rb
</programlisting>
<para>
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:
</para>
<para>
<literal>$ sudo ln -s /usr/bin/gem1.8.17 /usr/bin/gem</literal>
</para>
<para>
To check that Ruby Gems has been correctly installed, type the
following into your terminal:
</para>
<programlisting>
$ gem -v
</programlisting>
</sect3>
<sect3 id="sinatra">
<title>Sinatra</title>
<para>
With Ruby Gems setup, we can now easily install Sinatra. For
Linux or OSX type this in your terminal:
</para>
<para>
<literal>$ sudo gem install sinatra</literal>
</para>
<para>
and if you’re on Windows, enter the following at a command
prompt:
</para>
<para>
<literal>c:\\ &gt; gem install sinatra</literal>
</para>
</sect3>
<sect3 id="haml-1">
<title>Haml</title>
<para>
As with other DSLs and frameworks, Sinatra supports a wide range
of different templating engines.
<ulink url="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html">ERB</ulink>
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
<ulink url="http://haml.hamptoncatlin.com/">Haml</ulink> to
define our application templates.
</para>
<para>
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).
</para>
<para>
Installing Haml can be done in just a line using Ruby Gems as
follows:
</para>
<para>
<literal>$ gem install haml</literal>
</para>
</sect3>
<sect3 id="mongodb-1">
<title>MongoDB</title>
<para>
If you haven’t already downloaded and installed MongoDB from an
earlier chapter, please
<ulink url="http://www.mongodb.org/downloads">do so</ulink> now.
With Ruby Gems, Mongo can be installed in just one line:
</para>
<para>
<literal>$ gem install mongodb</literal>
</para>
<para>
We now require two further steps to get everything up and
running.
</para>
<sect4 id="data-directories">
<title>1.Data directories</title>
<para>
MongoDB stores data in the bin/data/db folder but won’t
actually create this directory for you. Navigate to where
you’ve downloaded and extracted Mongo and run the following
from terminal:
</para>
<programlisting>
sudo mkdir -p /data/db/
sudo chown `id -u` /data/db
</programlisting>
</sect4>
<sect4 id="running-and-connecting-to-your-server">
<title>2.Running and connecting to your server</title>
<para>
Once this is done, open up two terminal windows.
</para>
<para>
In the first, cd to your MongoDB bin directory or type in the
complete path to it. You’ll need to start mongod.
</para>
<programlisting>
$ ./bin/mongod
</programlisting>
<para>
Finally, in the second terminal, start the mongo shell which
will connect up to localhost by default.
</para>
<programlisting>
$ ./bin/mongo
</programlisting>
</sect4>
</sect3>
<sect3 id="mongodb-ruby-driver-1">
<title>MongoDB Ruby Driver</title>
<para>
As we’ll be using the
<ulink url="https://github.com/mongodb/mongo-ruby-driver">MongoDB
Ruby Driver</ulink>, we’ll also require the following gems:
</para>
<para>
The gem for the driver itself:
</para>
<programlisting>
$ gem install mongo
</programlisting>
<para>
and the driver’s other prerequisite, bson:
</para>
<programlisting>
$ gem install bson_ext
</programlisting>
<para>
This is basically a collection of extensions used to increase
serialization speed.
</para>
<para>
That’s it for our prerequisites!.
</para>
</sect3>
</sect2>
<sect2 id="tutorial">
<title>Tutorial</title>
<para>
To get started, let’s get a local copy of the practical
application working on our system.
</para>
<sect3 id="application-files">
<title>Application Files</title>
<para>
Clone
<ulink url="http://github.com/addyosmani/backbone-fundamentals">this</ulink>
repository and navigate to
<literal>/practicals/stacks/option3</literal>. Now run the
following lines at the terminal:
</para>
<programlisting>
ruby app.rb
</programlisting>
<para>
Finally, navigate to <code>http://localhost:4567/todo</code> to
see the application running successfully.
</para>
<para>
<emphasis role="strong">Note:</emphasis> The Haml layout files
for Option 3 can be found in the /views folder.
</para>
<para>
The directory structure for our practical application is as
follows:
</para>
<programlisting>
--public
----css
----img
----js
-----script.js
----test
--views
app.rb
</programlisting>
<para>
The <literal>public</literal> directory contains the scripts and
stylesheets for our application and uses HTML5 Boilerplate as a
base. You can find the Models, Views and Collections for this
section within <literal>public/js/scripts.js</literal> (however,
this can of course be expanded into sub-directories for each
component if desired).
</para>
<para>
<literal>scripts.js</literal> contains the following Backbone
component definitions:
</para>
<programlisting>
--Models
----Todo
--Collections
----TodoList
--Views
---TodoView
---AppView
</programlisting>
<para>
<literal>app.rb</literal> is the small Sinatra application that
powers our backend API.
</para>
<para>
Lastly, the <literal>views</literal> directory hosts the Haml
source files for our application’s index and templates, both of
which are compiled to standard HTML markup at runtime.
</para>
<para>
These can be viewed along with other note-worthy snippets of
code from the application below.
</para>
</sect3>
<sect3 id="backbone">
<title>Backbone</title>
<sect4 id="views-2">
<title>Views</title>
<para>
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
<literal>Todos.fetch()</literal> in the
<literal>initialize()</literal> method where we also bind to
the relevant events on the <literal>Todos</literal> collection
for when items are added or changed.
</para>
<programlisting language="javascript">
// Our overall **AppView** is the top-level piece of UI.
var AppView = Backbone.View.extend({
// Instead of generating a new element, bind to the existing skeleton of
// the App already present in the HTML.
el: $(&quot;#todoapp&quot;),
// Our template for the line of statistics at the bottom of the app.
statsTemplate: _.template($('#stats-template').html()),
// Delegated events for creating new items, and clearing completed ones.
events: {
&quot;keypress #new-todo&quot;: &quot;createOnEnter&quot;,
&quot;keyup #new-todo&quot;: &quot;showTooltip&quot;,
&quot;click .todo-clear a&quot;: &quot;clearCompleted&quot;
},
// At initialization
initialize: function() {
this.input = this.$(&quot;#new-todo&quot;);
Todos.on('add', this.addOne, this);
Todos.on('reset', this.addAll, this);
Todos.on('all', this.render, this);
Todos.fetch();
},
// Re-rendering the App just means refreshing the statistics -- the rest
// of the app doesn't change.
render: function() {
this.$('#todo-stats').html(this.statsTemplate({
total: Todos.length,
done:
….
</programlisting>
</sect4>
</sect3>
<sect3 id="collections-1">
<title>Collections</title>
<para>
In the TodoList collection below, we’ve set the
<literal>url</literal> property to point to
<literal>/api/todos</literal> to reference the collection’s
location on the server. When we attempt to access this from our
Sinatra-backed API, it should return a list of all the Todo
items that have been previously stored in Mongo.
</para>
<para>
For the sake of thoroughness, our API will also support
returning the data for a specific Todo item via
<literal>/api/todos/itemID</literal>. We’ll take a look at this
again when writing the Ruby code powering our backend.
</para>
<programlisting language="javascript">
// Todo Collection
var TodoList = Backbone.Collection.extend({
// Reference to this collection's model.
model: Todo,
// Save all of the todo items under the `&quot;todos&quot;` namespace.
// localStorage: new Store(&quot;todos&quot;),
url: '/api/todos',
// Filter down the list of all todo items that are finished.
done: function() {
return this.filter(function(todo){ return todo.get('done'); });
},
// Filter down the list to only todo items that are still not finished.
remaining: function() {
return this.without.apply(this, this.done());
},
// We keep the Todos in sequential order, despite being saved by unordered
// GUID in the database. This generates the next order number for new items.
nextOrder: function() {
if (!this.length) return 1;
return this.last().get('order') + 1;
},
// Todos are sorted by their original insertion order.
comparator: function(todo) {
return todo.get('order');
}
});
</programlisting>
</sect3>
<sect3 id="model">
<title>Model</title>
<para>
The model for our Todo application remains largely unchanged
from the versions previously covered in this book. It is however
worth noting that calling the function
<literal>model.url()</literal> within the below would return the
relative URL where a specific Todo item could be located on the
server.
</para>
<programlisting language="javascript">
// Our basic **Todo** model has `text`, `order`, and `done` attributes.
var Todo = Backbone.Model.extend({
idAttribute: &quot;_id&quot;,
// Default attributes for a todo item.
defaults: function() {
return {
done: false,
order: Todos.nextOrder()
};
},
// Toggle the `done` state of this todo item.
toggle: function() {
this.save({done: !this.get(&quot;done&quot;)});
}
});
</programlisting>
</sect3>
<sect3 id="rubysinatra">
<title>Ruby/Sinatra</title>
<para>
Now that we’ve defined our main models, views and collections
let’s get the CRUD operations required by our Backbone
application supported in our Sinatra API.
</para>
<para>
We want to make sure that for any operations changing underlying
data (create, update, delete) that our Mongo data store
correctly reflects these.
</para>
</sect3>
<sect3 id="app.rb">
<title>app.rb</title>
<para>
For <literal>app.rb</literal>, we first define the dependencies
required by our application. These include Sinatra, Ruby Gems,
the MongoDB Ruby driver and the JSON gem.
</para>
<programlisting language="ruby">
require 'rubygems'
require 'sinatra'
require 'mongo'
require 'json'
</programlisting>
<para>
Next, we create a new connection to Mongo, specifying any custom
configuration desired. If running a multi-threaded application,
setting the <quote>pool_size</quote> allows us to specify a
maximum pool size and <quote>timeout</quote> a maximum timeout
for waiting for old connections to be released to the pool.
</para>
<programlisting language="ruby">
DB = Mongo::Connection.new.db(&quot;mydb&quot;, :pool_size =&gt; 5, :timeout =&gt; 5)
</programlisting>
<para>
Finally we define the routes to be supported by our API. Note
that in the first two blocks - one for our application root
(<literal>/</literal>) and the other for our todo items route
<literal>/todo</literal> - we’re using Haml for template
rendering.
</para>
<programlisting language="ruby">
class TodoApp &lt; Sinatra::Base
get '/' do
haml :index, :attr_wrapper =&gt; '&quot;', :locals =&gt; {:title =&gt; 'hello'}
end
get '/todo' do
haml :todo, :attr_wrapper =&gt; '&quot;', :locals =&gt; {:title =&gt; 'Our Sinatra Todo app'}
end
</programlisting>
<para>
<literal>haml :index</literal> instructs Sinatra to use the
<literal>views/index.haml</literal> for the application index,
whilst `<literal>attr_wrapper</literal> is simply defining the
values to be used for any local variables defined inside the
template. This similarly applies Todo items with the template
`views/todo.haml’.
</para>
<para>
The rest of our routes make use of the <literal>params</literal>
hash and a number of useful helper methods included with the
MongoDB Ruby driver. For more details on these, please read the
comments I’ve made inline below:
</para>
<programlisting language="ruby">
get '/api/:thing' do
# query a collection :thing, convert the output to an array, map the _id
# to a string representation of the object's _id and finally output to JSON
DB.collection(params[:thing]).find.to_a.map{|t| from_bson_id(t)}.to_json
end
get '/api/:thing/:id' do
# get the first document with the id :id in the collection :thing as a single document (rather
# than a Cursor, the standard output) using find_one(). Our bson utilities assist with
# ID conversion and the final output returned is also JSON
from_bson_id(DB.collection(params[:thing]).find_one(to_bson_id(params[:id]))).to_json
end
post '/api/:thing' do
# parse the post body of the content being posted, convert to a string, insert into
# the collection #thing and return the ObjectId as a string for reference
oid = DB.collection(params[:thing]).insert(JSON.parse(request.body.read.to_s))
&quot;{\&quot;_id\&quot;: \&quot;#{oid.to_s}\&quot;}&quot;
end
delete '/api/:thing/:id' do
# remove the item with id :id from the collection :thing, based on the bson
# representation of the object id
DB.collection(params[:thing]).remove('_id' =&gt; to_bson_id(params[:id]))
end
put '/api/:thing/:id' do
# collection.update() when used with $set (as covered earlier) allows us to set single values
# in this case, the put request body is converted to a string, rejecting keys with the name '_id' for security purposes
DB.collection(params[:thing]).update({'_id' =&gt; to_bson_id(params[:id])}, {'$set' =&gt; JSON.parse(request.body.read.to_s).reject{|k,v| k == '_id'}})
end
# utilities for generating/converting MongoDB ObjectIds
def to_bson_id(id) BSON::ObjectId.from_string(id) end
def from_bson_id(obj) obj.merge({'_id' =&gt; obj['_id'].to_s}) end
end
</programlisting>
<para>
That’s it. The above is extremely lean for an entire API, but
does allow us to read and write data to support the
functionality required by our client-side application.
</para>
<para>
For more on what MongoDB and the MongoDB Ruby driver are capable
of, please do feel free to read their documentation for more
information.
</para>
<para>
If you’re a developer wishing to take this example further, why
not try to add some additional capabilities to the service:
</para>
<itemizedlist>
<listitem>
<para>
Validation: improved validation of data in the API. What
more could be done to ensure data sanitization?
</para>
</listitem>
<listitem>
<para>
Search: search or filter down Todo items based on a set of
keywords or within a certain date range
</para>
</listitem>
<listitem>
<para>
Pagination: only return the Nth number of Todo items or
items from a start and end-point
</para>
</listitem>
</itemizedlist>
</sect3>
<sect3 id="hamltemplates">
<title>Haml/Templates</title>
<para>
Finally, we move on to the Haml files that define our
application index (layout.haml) and the template for a specific
Todo item (todo.haml). Both of these are largely
self-explanatory, but it’s useful to see the differences between
the Jade approach we reviewed in the last chapter vs. using Haml
for this implementation.
</para>
<para>
Note: In our Haml snippets below, the forward slash character is
used to indicate a comment. When this character is placed at the
beginning of a line, it wraps all of the text after it into a
HTML comment. e.g
</para>
<para>
<literal>/ These are templates</literal>
</para>
<para>
compiles to:
</para>
<para>
<literal>&lt;!-- These are templates --&gt;</literal>
</para>
</sect3>
<sect3 id="index.haml">
<title>index.haml</title>
<programlisting language="html">
%head
%meta{'charset' =&gt; 'utf-8'}/
%title=title
%meta{'name' =&gt; 'description', 'content' =&gt; ''}/
%meta{'name' =&gt; 'author', 'content' =&gt; ''}/
%meta{'name' =&gt; 'viewport', 'content' =&gt; 'width=device-width,initial-scale=1'}/
/ CSS concatenated and minified via ant build script
%link{'rel' =&gt; 'stylesheet', 'href' =&gt; 'css/style.css'}/
/ end CSS
%script{'src' =&gt; 'js/libs/modernizr.min.js'}
%body
%div#container
%header
%div#main
= yield
%footer
/! end of #container
%script{'src' =&gt; 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'}
/ scripts concatenated and minified via ant build script
%script{'src' =&gt; 'js/mylibs/underscore.js'}
%script{'src' =&gt; 'js/mylibs/backbone.js'}
%script{'defer' =&gt; true, 'src' =&gt; 'js/plugins.js'}
%script{'defer' =&gt; true, 'src' =&gt; 'js/script.js'}
/ end scripts
</programlisting>
</sect3>
<sect3 id="todo.haml">
<title>todo.haml</title>
<programlisting language="html">
%div#todoapp
%div.title
%h1
Todos
%div.content
%div#create-todo
%input#new-todo{&quot;placeholder&quot; =&gt; &quot;What needs to be done?&quot;, &quot;type&quot; =&gt; &quot;text&quot;}/
%span.ui-tooltip-top{&quot;style&quot; =&gt; &quot;display:none;&quot;} Press Enter to save this task
%div#todos
%ul#todo-list
%div#todo-stats
/ Templates
%script#item-template{&quot;type&quot; =&gt; &quot;text/template&quot;}
&lt;div class=&quot;todo &lt;%= done ? 'done' : '' %&gt;&quot;&gt;
%div.display
&lt;input class=&quot;check&quot; type=&quot;checkbox&quot; &lt;%= done ? 'checked=&quot;checked&quot;' : '' %&gt; /&gt;
%div.todo-text
%span#todo-destroy
%div.edit
%input.todo-input{&quot;type&quot; =&gt; &quot;text&quot;, &quot;value&quot; =&gt;&quot;&quot;}/
&lt;/div&gt;
%script#stats-template{&quot;type&quot; =&gt; &quot;text/template&quot;}
&lt;% if (total) { %&gt;
%span.todo-count
%span.number &lt;%= remaining %&gt;
%span.word &lt;%= remaining == 1 ? 'item' : 'items' %&gt;
left.
&lt;% } %&gt;
&lt;% if (done) { %&gt;
%span.todo-clear
%a{&quot;href&quot; =&gt; &quot;#&quot;}
Clear
%span.number-done &lt;%= done %&gt;
completed
%span.word-done &lt;%= done == 1 ? 'item' : 'items' %&gt;
&lt;% } %&gt;
</programlisting>
</sect3>
</sect2>
<sect2 id="conclusions">
<title>Conclusions</title>
<para>
In this chapter, we looked at creating a Backbone application
backed by an API powered by Ruby, Sinatra, Haml, MongoDB and the
MongoDB driver. I personally found developing APIs with Sinatra a
relatively painless experience and one which I felt was on-par
with the effort required for the Node/Express implementation of
the same application.
</para>
<para>
This section is by no means the most comprehensive guide on
building complex apps using all of the items in this particular
stack. I do however hope it was an introduction sufficient enough
to help you decide on what stack to try out for your next project.
</para>
</sect2>
<sect2 id="advanced">
<title># <a name="advanced">Advanced</a></title>
<para>
</para>
</sect2>
<sect2 id="modular-javascript">
<title><a name="modularjs">Modular JavaScript</a></title>
<para>
When we say an application is modular, we generally mean it’s
composed of a set of highly decoupled, distinct pieces of
functionality stored in modules. As you probably know, loose
coupling facilitates easier maintainability of apps by removing
dependencies where possible. When this is implemented efficiently,
its quite easy to see how changes to one part of a system may
affect another.
</para>
<para>
Unlike some more traditional programming languages however, the
current iteration of JavaScript (ECMA-262) doesn’t provide
developers with the means to import such modules of code in a
clean, organized manner. It’s one of the concerns with
specifications that haven’t required great thought until more
recent years where the need for more organized JavaScript
applications became apparent.
</para>
<para>
Instead, developers at present are left to fall back on variations
of the module or object literal patterns. With many of these,
module scripts are strung together in the DOM with namespaces
being described by a single global object where it’s still
possible to incur naming collisions in your architecture. There’s
also no clean way to handle dependency management without some
manual effort or third party tools.
</para>
<para>
Whilst native solutions to these problems will be arriving in ES
Harmony, the good news is that writing modular JavaScript has
never been easier and you can start doing it today.
</para>
<para>
In this next part of the book, we’re going to look at how to use
AMD modules and RequireJS for cleanly wrapping units of code in
your application into manageable modules.
</para>
</sect2>
<sect2 id="organizing-modules-with-requirejs-and-amd">
<title><a name="organizingmodules">Organizing modules with RequireJS
and AMD</a></title>
<para>
In case you haven’t used it before,
<ulink url="http://requirejs.org">RequireJS</ulink> is a popular
script loader written by James Burke - a developer who has been
quite instrumental in helping shape the AMD module format, which
we’ll discuss more shortly. Some of RequireJS’s capabilities
include helping to load multiple script files, helping define
modules with or without dependencies and loading in non-script
dependencies such as text files.
</para>
<para>
So, why use RequireJS with Backbone? Although Backbone is
excellent when it comes to providing a sanitary structure to your
applications, there are a few key areas where some additional help
could be used:
</para>
<orderedlist numeration="arabic">
<listitem>
<para>
Backbone doesn’t endorse a particular approach to
modular-development. Although this means it’s quite open-ended
for developers to opt for classical patterns like the
module-pattern or Object Literals for structuring their apps
(which both work fine), it also means developers aren’t sure
of what works best when other concerns come into play, such as
dependency management.
</para>
</listitem>
</orderedlist>
<para>
RequireJS is compatible with the AMD (Asynchronous Module
Definition) format, a format which was born from a desire to write
something better than the <quote>write lots of script tags with
implicit dependencies and manage them manually</quote> approach to
development. In addition to allowing you to clearly declare
dependencies, AMD works well in the browser, supports string IDs
for dependencies, declaring multiple modules in the same file and
gives you easy-to-use tools to avoid polluting the global
namespace.
</para>
<orderedlist numeration="arabic">
<listitem override="2">
<para>
Let’s discuss dependency management a little more as it can
actually be quite challenging to get right if you’re doing it
by hand. When we write modules in JavaScript, we ideally want
to be able to handle the reuse of code units intelligently and
sometimes this will mean pulling in other modules at run-time
whilst at other times you may want to do this dynamically to
avoid a large pay-load when the user first hits your
application.
</para>
</listitem>
</orderedlist>
<para>
Think about the GMail web-client for a moment. When users
initially load up the page on their first visit, Google can simply
hide widgets such as the chat module until a user has indicated
(by clicking <quote>expand</quote>) that they wish to use it.
Through dynamic dependency loading, Google could load up the chat
module only then, rather than forcing all users to load it when
the page first initializes. This can improve performance and load
times and can definitely prove useful when building larger
applications.
</para>
<para>
I’ve previously written
<ulink url="http://addyosmani.com/writing-modular-js">a detailed
article</ulink> covering both AMD and other module formats and
script loaders in case you’d like to explore this topic further.
The takeaway is that although it’s perfectly fine to develop
applications without a script loader or clean module format in
place, it can be of significant benefit to consider using these
tools in your application development.
</para>
<sect3 id="writing-amd-modules-with-requirejs">
<title>Writing AMD modules with RequireJS</title>
<para>
As discussed above, the overall goal for the AMD format is to
provide a solution for modular JavaScript that developers can
use today. The two key concepts you need to be aware of when
using it with a script-loader are a <literal>define()</literal>
method for facilitating module definition and a
<literal>require()</literal> method for handling dependency
loading. <literal>define()</literal> is used to define named or
unnamed modules based on the proposal using the following
signature:
</para>
<programlisting language="javascript">
define(
module_id /*optional*/,
[dependencies] /*optional*/,
definition function /*function for instantiating the module or object*/
);
</programlisting>
<para>
As you can tell by the inline comments, the
<literal>module_id</literal> is an optional argument which is
typically only required when non-AMD concatenation tools are
being used (there may be some other edge cases where it’s useful
too). When this argument is left out, we call the module
<quote>anonymous</quote>. When working with anonymous modules,
the idea of a module’s identity is DRY, making it trivial to
avoid duplication of filenames and code.
</para>
<para>
Back to the define signature, the dependencies argument
represents an array of dependencies which are required by the
module you are defining and the third argument
(<quote>definition function</quote>) is a function that’s
executed to instantiate your module. A barebone module
(compatible with RequireJS) could be defined using
<literal>define()</literal> as follows:
</para>
<programlisting language="javascript">
// A module ID has been omitted here to make the module anonymous
define(['foo', 'bar'],
// module definition function
// dependencies (foo and bar) are mapped to function parameters
function ( foo, bar ) {
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
});
</programlisting>
<sect4 id="alternate-syntax">
<title>Alternate syntax</title>
<para>
There is also a
<ulink url="http://requirejs.org/docs/whyamd.html#sugar">sugared
version</ulink> of <literal>define()</literal> available that
allows you to declare your dependencies as local variables
using <literal>require()</literal>. This will feel familiar to
anyone who’s used node, and can be easier to add or remove
dependencies. Here is the previous snippet using the alternate
syntax:
</para>
<programlisting language="javascript">
// A module ID has been omitted here to make the module anonymous
define(function(require){
// module definition function
// dependencies (foo and bar) are defined as local vars
var foo = require('foo'),
bar = require('bar');
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
});
</programlisting>
<para>
The <literal>require()</literal> method is typically used to
load code in a top-level JavaScript file or within a module
should you wish to dynamically fetch dependencies. An example
of its usage is:
</para>
<programlisting language="javascript">
// Consider 'foo' and 'bar' are two external modules
// In this example, the 'exports' from the two modules loaded are passed as
// function arguments to the callback (foo and bar)
// so that they can similarly be accessed
require(['foo', 'bar'], function ( foo, bar ) {
// rest of your code here
foo.doSomething();
});
</programlisting>
<para>