15. MVC Benefits
Structure
Classes, inheritance, common patterns.
Modular
Communication via events, lousily coupled & testable components.
Common services
Back and forward history, clients-side url resources, utilities.
Persistence layers
RESTful sync, local storage, web sockets and more.
Community
Patterns, mixins, conferences and more.
16. Challenges
• Going out of the box
• Nested models
• Complex ajax requests
• Understanding the limitations
• Its still hard
18. To mvc, or not to mvc ?
Use for one page apps
Use for complex client-side UIs & crud
Use not only for UI sugar
Use not for just rendering HTML
Use not for inflexible backends
30. Events
• Consists of on, off & trigger methods
• All Backbone modules can trigger events
• All Javascript object can be extended with
the Backbone events module
31. Event example
Event triggered inside User class when name is changed
this.trigger("change:name", "Mr Hilmarsson");
Bind to a name change event
user.on("change:name", function( name ) {
! alert( "Name changed to " + name );
});
40. Views
• Bridge the gap between the HTML and
models
• DOM element ( this.el ) represents the
context
• Uses jQuery / Zepto / ender for DOM
manipulation
• Listens for UI events & model events
• Use render method to create view
46. Router & History
• Provides a way to map URL resources
• Enables client-side back & forward
navigation
• Use Hash-change by default. Supports
push state ( History API )
47. Be Careful!
• Its stateful !
• Its not easy
• Don’t set navigate trigger to true
49. History - example
Start listening for hash-change events
// Start the history
Backbone.history.start();
Use html5 history API
// Start the history
Backbone.history.start({pushState: true});
52. Tips & Tricks
• Tip #1 - Bootstrapping data
• Tip #2 - Async user interfaces
• Tip #3 - Nested models
• Tip #4 - Custom ajax requests
• Tip #5 - Zombies to heaven
• Tip #6 - The toolbox
• Tip #7 - Test, test, test
• Tip #8 - CoffeeScript
• Tip #9 - Remember the basics
• Tip #10 - Bonus points
54. Bootstrapping data
• Using fetch extends waiting time
• Possible to bootstrap the most important
data when the page is rendered
• No loading spinners !
55. Bootstrapping Data
The code
// Current user
APP.currentUser = new APP.Models.User(<%= @current_user.to_json.html_safe %>);
// Notes
APP.notes.reset(<%= @notes.to_json.html_safe %>);
After render
// Current user
APP.currentUser = new APP.Models.User({
id: 1, username: "hjortureh",
name: "Hjortur Hilmarsson",
avatar: "avatar.gif"
});
// Notes
APP.notes.reset([
{ id: 1, text: "Note 1" },
{ id: 1, text: "Note 2" },
{ id: 1, text: "Note 3" }
]);
59. Importance of speed
Amazon
100 ms of extra load time caused a 1% drop in
sales (source: Greg Linden, Amazon).
Google
500 ms of extra load time caused 20% fewer
searches (source: Marrissa Mayer, Google).
Yahoo!
400 ms of extra load time caused a 5–9%
increase in the number of people who clicked
“back” before the page even loaded (source:
Nicole Sullivan, Yahoo!).
37 Signals - Basecamp
500 ms increase in speed on basecamp.com
resulted in 5% improvement in conversion rate.
61. Async user interfaces
• Models are optimistic by default
• UI is updated before server response
• Use cid as a unique identifier on the client
• No loading spinners !
65. Nested models
• Nested models are common
• No official way of doing it
• Overwrite parse after ajax request
• Overwrite toJSON before ajax request
• Backbone-relational mixin could help
72. Zombies to heaven
• Its not enough to remove views from the
DOM
• Events must be released so you don’t have
zombies walking around
73. Zombies to heaven
// same as this.$el.remove();
this.remove();
// remove all models bindings
// made by this view
this.model.off( null, null, this );
// unbind events that are
// set on this view
this.off();
75. Use the toolbox
• Underscore has some wonderful methods
• isFunction, isObject, isString, isNumber,
isDate & more.
• Underscore: http://
documentcloud.github.com/underscore
76. Underscore
Line 865 from the Backbone.js code.
// Underscore methods that we want to implement on the Collection.
var methods = ['forEach', 'each', 'map', 'reduce', 'reduceRight', 'find',
'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any',
'include', 'contains', 'invoke', 'max', 'min', 'sortBy', 'sortedIndex',
'toArray', 'size', 'first', 'initial', 'rest', 'last', 'without', 'indexOf',
'shuffle', 'lastIndexOf', 'isEmpty', 'groupBy'];
// Mix in each Underscore method as a proxy to `Collection#models`.
_.each(methods, function(method) {
Collection.prototype[method] = function() {
return _[method].apply(_, [this.models].concat(_.toArray(arguments)));
};
});
78. Testing
• Recommend Jasmine for testing
• Recommend Sinon to fake the server
• jQuery-jasmine to test views
• Use setDomLibrary method to fake jQuery
79. Jasmine with fake server & spy
it('Should sync correctly', function () {
// mockup data
var note = new APP.Models.Note({ text: "Buy some eggs" });
// fake server
this.server = sinon.fakeServer.create();
// fake response
this.server.respondWith( "POST", "/notes",
[ 200,
{"Content-Type": "application/json"},
'{ "id": 1, "text": "Remember the milk" }' ]
);
// spy on sync event
var spy = sinon.spy();
note.on("sync", spy );
// save model
note.save();
// server repsonse
this.server.respond();
// assert
expect( spy ).toHaveBeenCalledOnce();
expect( spy ).toHaveBeenCalledWith( note );
expect( note.get("text") ).toEqual( "Remember the milk" );
// restore fake server
this.server.restore();
});
82. CoffeeScript
• Advanced programing language
• Compiles to javascript
• Same creator of Backbone and
CoffeeScript
• Integrates well with Backbone
83. Coffee Script example
Extending Backbone module
class TodoList extends Backbone.View
Double arrow to bind to the context
Use @ instead of this
Last line is the return value, returns this
_.bindAll( this, 'render' )
render: =>
@$el.html( @template( @.model.toJSON() ))
@
Need to call super on parent constructors
initialize: ->
! super
85. The basics
• The basics still apply with MVC in place
• Minimize ajax requests
• Keep your views thin & models fat
• Understanding Javascript is the key