Backbone.js helps structure you javascript application code in a scalable way.
In this keynote I demonstrate how to use it in a simple walk-through example, and discuss the advantages of using an MVC framework.
12. Application Structure
• Each “page” is just a
div
• “Page” can be a full
page or partial
<body>
<div class="page">
<h1>About Page</h1>
</div>
<div class="page">
<h1>Main Page</h1>
</div>
<div class="page">
<h1>Item Info</h1>
</div>
</body>
Thursday, September 12, 13
13. Application Structure
• Navigating in the app is just calling a
route function
• Route function slides divs in-and-out
help: function() {
alert('What can I help you with ?');
}
Thursday, September 12, 13
16. Models
• Models store your data
• Models have no visual representation
• Functionality for managing changes
Thursday, September 12, 13
17. Views
• A View provides the visual representation
of a model
Task Model
Thursday, September 12, 13
18. Collections
• Models are usually grouped in collections
* Task Model
* Task Model
* Task Model
Daily
Tasks
Walk the dog
Water the plans
Thursday, September 12, 13
19. Backbone Benefits
• Good separation of
concerns
• Best for large client-
side applications
Thursday, September 12, 13
20. What Backbone Is Not
• It’s not a framework
• So it’s ok to use only parts of it
Thursday, September 12, 13
21. What Backbone Is Not
• It’s not for small apps that just
“show data”
• Backbone assumes client-side logic
Thursday, September 12, 13
22. What Backbone Is Not
• It will never get in your way :)
Thursday, September 12, 13
28. Task View
global.views.TaskView = Backbone.View.extend({
tagName: "div",
className: "task",
events: {
"click" : "handle_click"
},
Define a new View
Thursday, September 12, 13
29. Task View
global.views.TaskView = Backbone.View.extend({
tagName: "div",
className: "task",
events: {
"click" : "handle_click"
},
Specify HTML element
Thursday, September 12, 13
30. Task View
global.views.TaskView = Backbone.View.extend({
tagName: "div",
className: "task",
events: {
"click" : "handle_click"
},
Define Event Handlers
name of a method that will be
called when the view is clicked
Thursday, September 12, 13
31. View Rendering
• render() method of a view is used to
render it to HTML
• Usually implemented with client side
template engine
Thursday, September 12, 13
33. Task View
render: function() {
this.$el.html( this.template( this.model.toJSON()));
return this;
},
template: Handlebars.compile($('#task-template').html())
Paint The View onto HTML
Thursday, September 12, 13
34. Task View
render: function() {
this.$el.html( this.template( this.model.toJSON()));
return this;
},
template: Handlebars.compile($('#task-template').html())
Handlebars is used as a template engine
Thursday, September 12, 13
35. Task View
initialize: function(opts) {
this.model.on('change', this.render, this );
},
handle_click: function() {
if ( this.model.get('completed') ) {
this.model.set('completed', false);
} else {
this.model.set('completed', true);
}
},
initialize is called from a view’s constructor
Thursday, September 12, 13
36. Task View
initialize: function(opts) {
this.model.on('change', this.render, this );
},
handle_click: function() {
if ( this.model.get('completed') ) {
this.model.set('completed', false);
} else {
this.model.set('completed', true);
}
},
We use it to bind event handlers on the model
Thursday, September 12, 13
37. Task View
initialize: function(opts) {
this.model.on('change', this.render, this );
},
handle_click: function() {
if ( this.model.get('completed') ) {
this.model.set('completed', false);
} else {
this.model.set('completed', true);
}
},
Implementing the clicks handler
Thursday, September 12, 13
38. Main App View
global.views.AppView = Backbone.View.extend({
el: $('body'),
events: {
"click .add-btn": "add_task"
},
add_task: function() {
var task_description = this.$el.find('input').val();
var tm = new global.models.Task({ text: task_description });
var tv = new global.views.TaskView({model: tm});
this.$el.find('ul').append(tv.render().el);
this.$el.find('input').val('');
}
});
Thursday, September 12, 13
39. Take Aways
• Models keep data
• Views show data
• Views listen for model changes using on
• Views listen for DOM changes using
events
Thursday, September 12, 13
40. Lab
• Add a “Priority” field to a task
• Render high priority tasks in red, medium
priority tasks in yellow and normal in
green
Thursday, September 12, 13
41. Backbone Router
• A Router connects URL with application
state
• This allows internal bookmarking and
history management
Thursday, September 12, 13
42. Hello Router
• You only
need
one
• Defines
routes
and
handlers
var router = new (Backbone.Router.extend({
routes: {
'' : 'home',
'help' : 'help'
},
home: function() {
alert('WElcome home');
},
help: function() {
alert('What can I help you with ?');
}
}))();
Backbone.history.start({ pushState: true } );
Thursday, September 12, 13
43. Changing State
• Use router.navigate( url ) to
change state
• Pass { trigger: true } if you need to
also trigger the route
Thursday, September 12, 13
44. Demo
• Let’s add a View Task page
• Shows a specific task in details
• Then connect the pages using a router
Thursday, September 12, 13
46. Models & The Server
• Set the urlRoot property of a model to
allow it to sync with your server
Thursday, September 12, 13
47. Models & The Server
Model Id
Model
Method
HTTP Method Url
id == 1 .fetch() GET /todos/1
id == 1 .save() PUT /todos/1
no id .fetch() GET /todos
no id .save() POST /todos
Thursday, September 12, 13
48. Server Events
• request event is triggered when sync
starts
• change event is triggered when an
attribute value has changed
• sync event is triggered when save is
completed (i.e. data is saved on server)
Thursday, September 12, 13
49. Server URLs
• POST /items => return a new item
• GET /items/id => return an existing
item by its id
• PUT /items/id => change existing
item by its id
Thursday, September 12, 13
55. Collection Actions
• col.length : number of models in
the collection
• col.add(m) : add a model
• col.remove(m) : remove a model
Thursday, September 12, 13
56. Collection Actions
• col.at( index ) : get a model at a
specific index
• col.get( id ) : get a model by its id
Thursday, September 12, 13
60. Collection Views
• It’s ok to create a view for a collection
• Just pass in the collection to the view’s
new method
• Render delegates its job to subviews
• Demo: Create a collection view for
TasksGroup
Thursday, September 12, 13
61. Collection Views
render: function() {
var $el = this.$el;
$el.html('');
this.collection.forEach(function(model) {
var v = new app.views.Task( { model: model } );
$el.append( v.render() );
});
return $el;
},
Thursday, September 12, 13
62. Collection Views
render: function() {
var $el = this.$el;
$el.html('');
this.collection.forEach(function(model) {
var v = new app.views.Task( { model: model } );
$el.append( v.render() );
});
return $el;
},
Pop Quiz:
What can go wrong ?
Thursday, September 12, 13
63. Managing Subviews
• If subviews also listen for model events,
you will need to stop listening before
removing the container view
• Solution: keep a list of subviews in
container
Thursday, September 12, 13
64. More Collection Views
• Same data, different views
• Let’s create a counter view
• Show total number of tasks
Thursday, September 12, 13
65. Collections
initialize: function() {
var cv = new global.views.CounterView(
{ tasks: this.tasks }).render();
this.$el.append( cv.el );
this.tasks.on('add', cv.render, cv );
this.tasks.on('remove', cv.render, cv);
},
In appview.js
Collections trigger events when models are
added or removed
Thursday, September 12, 13
67. Lab
• Modify CounterView so it will also display
the number of unfinished tasks
Thursday, September 12, 13
68. Other Collection Methods
• forEach (function(item) { ... } )
• find
• filter
• include
• toArray
Thursday, September 12, 13
69. Collection and Server
• Retrieve a collection from the server
using fetch()
• url is a property of collection
• change event is triggered if server state is
different
Thursday, September 12, 13
71. Collection Events
• reset event is triggered after fetch() or
reset()
• add() event is triggered when a model
is added to a collection
• remove() event is triggered when a
model is removed from a collection
Thursday, September 12, 13
74. Extending Backbone
• Backbone is easy to extend:
• You can add functions to the
Backbone namespace
• You can override Backbone’s methods
Thursday, September 12, 13
75. Try This
• Add function toggle() to Backbone.Model
to toggle bool values (true / false)
Thursday, September 12, 13
76. Try This
• Create a TemplateView that acts like a
Backbone.View with a simple template
rendering functionality built-in
Thursday, September 12, 13
77. Backbone Extensions
• JS Libs that extend Backbone
• Really long list at:
https://github.com/jashkenas/backbone/
wiki/Extensions,-Plugins,-Resources
Thursday, September 12, 13
78. Nested Collections
• A collection that
“has” another
collection
• Example: Inbox and
Messages
Thursday, September 12, 13
81. Let’s Code This
• Models:
• Mailbox model
• Message model
• Collections:
• Mailbox collection (for messages)
• Folders collection (for mailboxes)
Thursday, September 12, 13
82. This works. But...
• Given a message item, can you tell in
which mailbox it is ?
• How do you move a message from one
inbox to another ?
Thursday, September 12, 13
83. Backbone-Relational
• A plugin for managing relations between
collections
• Adds RelationalModel
• http://backbonerelational.org/
Thursday, September 12, 13
86. Pagination
• Collection only stores partial data
• Add methods to collection:
• goToNextPage()
• goToPreviousPage()
• goToPage()
Thursday, September 12, 13
87. Pagination
• Need to override Backbone.sync to allow
sending custom parameters to the server
Thursday, September 12, 13
88. Backbone.Sync
• sync(method, model, [options])
• method: create / read / update / delete
• model: model or collection
• options: success and error callbacks
Thursday, September 12, 13
89. Backbone.Sync options
• Use a global Backbone.sync to enable
application wide overriding
• Use a model/collection specific sync to
have only that collection use your sync
Thursday, September 12, 13
90. Backbone.Sync Demo
• Let’s write a cacheable model that adds
two methods:
• cache()
• invalidate()
• After cache(), all read requests should
return the cached copy
Thursday, September 12, 13
91. Lab: Fill in the missing parts
Backbone.CachedModel = Backbone.Model.extend({
cache: function() {
},
invalidate: function() {
},
sync: function(method, model, opts) {
}
});
Thursday, September 12, 13
92. Take Aways
• Backbone.sync allows full control on the
syncing process
• If you just need to add functionality,
consider listening for sync events
Thursday, September 12, 13
93. Pagination
• Use a custom (paginated) collection
• Add a sync method so it’ll send your
pagination params to the server
• AND Someone already did it :)
Thursday, September 12, 13
94. The Backbone Way
• A special collection is added using the
Paginator plugin
• Backbone.Paginator.requestPager
Thursday, September 12, 13
95. Other Params
• Paginated Collection needs:
• paginator_core: an object describing
how to interact with the server
• paginator_ui: an object describing
how to display the info
• server_api: an object describing the
parameters to send
• Code: https://github.com/backbone-
paginator/backbone.paginator
Thursday, September 12, 13
98. Other Plugins
• Backbone.localStorage will let you store
your models locally
https://github.com/jeromegn/
Backbone.localStorage
Thursday, September 12, 13
99. Other Plugins
• Backbone Forms will automatically
create form controls for you
• Also adds validation code
• https://github.com/powmedia/
backbone-forms
Thursday, September 12, 13
100. Other Plugins
• Backbone Stickit will let you have two-
ways data binding for your views
• http://nytimes.github.io/backbone.stickit/
Thursday, September 12, 13
101. Extending Backbone
• Extending Backbone is easy
• Just create more models, views or
controllers
• Sometimes you’ll need to override
Backbone methods
Thursday, September 12, 13
102. Benefits
• Lifts big apps
• Scalable and very
stable
• No magic
• Extensible
Thursday, September 12, 13
103. Dark Side
• Not suitable for
small apps
• Can be confusing
for new developers
• Can sometimes add
clutter
Thursday, September 12, 13
104. Thank You
• Ynon Perek
• me@ynonperek.com
• ynonperek.com
Thursday, September 12, 13