SlideShare a Scribd company logo
MVC Frameworks
 in Javascript
   Hjörtur Hilmarsson
       @hjortureh
Agenda


• Why MVC in Javascript ?
• Backbone & Spine
• Backbone fundamentals
• Backbone Tips & Tricks
Why MVC ?
“The world web
  is changed”
Evolution of web apps
Help!
Contact Us
Markup

<form>

!   <!-- Name input -->
!   <input id="name" name="name" type="text" placeholder="What is your name?" required />

!   <!-- Email input -->
!   <input id="email" name="email" type="email" placeholder="What is your email?" required />

!   <!-- Message input -->
!   <textarea id="message" name="message" placeholder="Hello!" required ></textarea>

!   <!--Send button -->
!   <input id="submit" name="submit" type="submit" value="Send" />

!   <!-- Message label -->
!   <span id="message" ></span>

</form>
Javascript - Old style

$("form").submit(function( e ) {
!   !    !   !
!   e.preventDefault();

!     // get values
      var $form = $(this);
      var data = {
          name: $form.find("[name=name]").val(),
          email: $form.find("[name=email]").val(),
          message: $form.find("[name=message]").val()
      };

      // ajax request
      $.ajax({
          type: "post",
          url: "/enquiry",
          contentType: "application/json",
          dataType: "json",
          data: data,
          success: function() {
               $form.find("#message").text("Message posted").fadeIn();
          },
          error: function() {
               $form.find("#message").text("Sorry, there was an error").fadeIn();
          }
      });
});
Controller - MVC style

$("form").submit(function( e ) {
!   !    !   !
!   e.preventDefault();

!     // get values
!     var $form = $(this);
!     var data = {
!     !   name: $form.find("[name=name]").val(),
!     !   email: $form.find("[name=email]").val(),
!     !   message: $form.find("[name=message]").val()
!     };

!     // model
!     var enquiry = new Enquiry( data );
!
!     enquiry.save(
!     !   function() {
!     !   !    $form.find("#message").text("Message posted");
!     !   },
!     !   function() {
!     !   !    $form.find("#message").text("Sorry, there was an error");
!     !   }
!     );
});
Model - MVC style

// constructor
var Enquiry = function( data ) {
!   this.data = data;
};

// save method
Enquiry.prototype.save = function( success, error ) {

!    // ajax request
!    $.ajax({
!    !   type: "post",
!    !   url: "/enquiry",
!    !   contentType: "application/json",
!    !   dataType: "json",
!    !   data: this.data,
!    !   success: success,
!    !   error: error
!    });

};
Backbone.js controller view
var   ContactUs = Backbone.View.extend({
!
!     // local variables
!     el: $("form").get(0),
!     events: { "submit": "submit" }
!     model: new Enquiry,

!     // constructor
!     initialize: function() {
!     !   this.model.bind("create", create, this );!
!     !   this.model.bind("error", error, this );!
!     },

!     // submit event
!     submit: function( e ) {
!     !   e.preventDefault();
!     !
!     !   var data = {
!     !   !    name: this.$("[name=name]").val(),
!     !   !    email: this.$("[name=email]").val(),
!     !   !    message: this.$("[name=message]").val()
!     !   };

!     !    this.model.save();
!     },

!     // success callback
!     create: function() {
!     !   this.$("#message").text("Message posted");
!     },

!     // error callback
!     error: function() {
!     !   this.$("#message").text("Sorry, there was an error");
!     }

});
Backbone.js model

 var Enquiry = Backbone.Model.extend({});
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.
Challenges


• Going out of the box
• Nested models
• Complex ajax requests
• Understanding the limitations
• Its still hard
Challenges




TodoMVC - http://addyosmani.github.com/todomvc/
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
Web Apps
Backbone & Spine
• Created 2010 by Jeremy Ashkenas
• File size 5.4k
• Depends on Underscore.js ( 4k )
• Very popular
http://blog.fogcreek.com/the-trello-tech-stack/
https://engineering.linkedin.com/mobile/linkedin-ipad-using-local-storage-snappy-mobile-apps
Spine


• Inspired by Backbone
• Written in CoffeeScript by Alex McCaw
• File size 7k
• Introduced async UI concept
Text



http://hjortureh.tumblr.com/post/22117245794/spine-js-vs-backbone-js
Fundamentals
Modules

• Events
• Models
• Collections
• Views
• Routes
• History
Events
Events



• Consists of on, off & trigger methods
• All Backbone modules can trigger events
• All Javascript object can be extended with
  the Backbone events module
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 );
  });
Models
Models


• Wrapper for JSON & syncing via JSON
• RESTful by default. Overwrite sync
  method to change persistence logic.
• Communicates via events ( create, change,
  destroy, sync, error, add , remove )
• Can handle validation
Model


var Todo = Backbone.Model.extend({

      defaults: {
         done: false
      },

      toggle: function() {
         this.save({done: !this.get("done")});
      },

      clear: function() {
        this.destroy();
      }

});
TodoMVC - example




   http://addyosmani.github.com/todomvc/architecture-examples/backbone/index.html
Collections
Collections


• List of models
• Fires events for collection and the models
• Keeps models sorted
• Includes many utility methods
Collection

var TodoList = Backbone.Collection.extend({

      model: Todo,

      done: function() {
         return this.filter(function(todo){ return todo.get('done'); });
      },

      remaining: function() {
         return this.without.apply(this, this.done() );
      },

      comparator: function(todo) {
        return todo.get('order');
      }

});
Views
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
Organizing views




       1:1
       View    Model
Todo view

var TodoView = Backbone.View.extend({

    tagName:     "li",

    template: _.template($('#item-template').html()),

    events: {
       "click .check"                : "toggleDone"
    },

    initialize: function() {
      _.bindAll(this, 'render' );

         this.model.bind('change', this.render );
    },

    render: function() {
       $(this.el).html(this.template(this.model.toJSON()));
       return this;
    },

    toggleDone: function() {
      this.model.toggle();
    }

    ...
}
Template



<script type="text/template" id="item-template">

  <div class="todo <%= done ? 'done' : '' %>">
    <div class="display">
      <input class="check" type="checkbox" <%= done ? 'checked="checked"' : '' %> />
      <label class="todo-content"><%= content %></label>
      <span class="todo-destroy"></span>
    </div>
    <div class="edit">
      <input class="todo-input" type="text" value="<%= content %>" />
    </div>
  </div>

</script>
App view

var AppView = Backbone.View.extend({

!   el: $("#todoapp"),

!   !     initialize: function() {
!   !     _.bindAll(this, 'addOne', 'addAll', 'render' );

!   !     Todos.on('add',     this.addOne);
!   !     Todos.on('reset',   this.addAll);

!   !     Todos.fetch();
!   },

!   addOne: function(todo) {
!   !   var view = new TodoView({model: todo});
!   !   this.$("#todo-list").append(view.render().el);
!   },

!   addAll: function() {
!   !   Todos.each(this.addOne);
!   }

!   ...

}
Router & History
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 )  
Be Careful!



• Its stateful !
• Its not easy
• Don’t set navigate trigger to true
Router


APP.Router = Backbone.Router.extend({

  routes: {
     "new": "newNote",
     ":id": "editNote",
     "": "home"
  },

  home: function() {
     APP.appView.home();
  },

  newNote: function() {
     APP.appView.newNote();
  },

  editNote: function( id ) {
    APP.appView.editNote( id );
  }

});
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});
Demo
Backbone tips & tricks
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
Tip #1
Bootstrapping data
Bootstrapping data



• Using fetch extends waiting time
• Possible to bootstrap the most important
  data when the page is rendered
• No loading spinners !
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" }
 ]);
Demo
Twitter demo
Tip #2
Async User Interfaces
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.
Importance of speed
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 !
Demo
Tip #3
Nested Models
Question

   Has many




Answers
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
Nested models
 var Question = Backbone.Model.extend({


   initialize: function() {

        // collection instance
        this.answers = new Answers;

   },


   parse: function(resp, xhr) {

        // fill nested model
        if( _.isArray( resp.answers ) ) {
            this.answers.reset( resp.answers );
        }

        return resp;

   },


   toJSON: function() {

        // send nested models
        return $.extend(
           this.attributes(), {
             answers: this.answers.toJSON()
           }
        );
   }

 });
Tip #4
Custom ajax requests
Custom ajax request



• Sometimes RESTful methods are not
  enough
• Example: Sorting tasks in to-do list
Sorting - Custom request



saveOrder: function() {
    !
!   var ids = this.pluck("id");
!
!   window.$.ajax({
!   !    url: "/tasks/reorder",
!   !    data: {
!   !    !   ids: ids
!   !    },
!   !    type: "POST",
!   !    dataType: "json",
!   !    complete: function() {
!   !    !   // Handle response
!   !    }
!   });
!
}
Tip #5
Send zombies to heaven
Zombies to heaven



• Its not enough to remove views from the
  DOM
• Events must be released so you don’t have
  zombies walking around
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();
Tip #6
Use the toolbox
Use the toolbox


• Underscore has some wonderful methods
• isFunction, isObject, isString, isNumber,
  isDate & more.
• Underscore: http://
  documentcloud.github.com/underscore
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)));
      };
  });
Tip #7
Test, test, test
Testing


• Recommend Jasmine for testing

• Recommend Sinon to fake the server

• jQuery-jasmine to test views

• Use setDomLibrary method to fake jQuery
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();

 });
Demo
Tip #8
CoffeeScript
CoffeeScript


• Advanced programing language
• Compiles to javascript
• Same creator of Backbone and
  CoffeeScript
• Integrates well with Backbone
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
Tip #9
The Basics
The basics


• The basics still apply with MVC in place
• Minimize ajax requests
• Keep your views thin & models fat
• Understanding Javascript is the key
Tip #10
 Bonus
Bonus points



• Read the documentation
• Read the source code
• Just do it !
Tack så mycket
  Hjörtur Elvar Hilmarsson
        @hjortureh

More Related Content

What's hot

jQuery: Events, Animation, Ajax
jQuery: Events, Animation, AjaxjQuery: Events, Animation, Ajax
jQuery: Events, Animation, Ajax
Constantin Titarenko
 
jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009
Remy Sharp
 
Angular JS blog tutorial
Angular JS blog tutorialAngular JS blog tutorial
Angular JS blog tutorial
Claude Tech
 
jQuery Presentation
jQuery PresentationjQuery Presentation
jQuery Presentation
Rod Johnson
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
velveeta_512
 
jQuery in the [Aol.] Enterprise
jQuery in the [Aol.] EnterprisejQuery in the [Aol.] Enterprise
jQuery in the [Aol.] Enterprise
Dave Artz
 
jQuery Essentials
jQuery EssentialsjQuery Essentials
jQuery Essentials
Bedis ElAchèche
 
Sane Async Patterns
Sane Async PatternsSane Async Patterns
Sane Async Patterns
TrevorBurnham
 
Jquery Complete Presentation along with Javascript Basics
Jquery Complete Presentation along with Javascript BasicsJquery Complete Presentation along with Javascript Basics
Jquery Complete Presentation along with Javascript Basics
EPAM Systems
 
AnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFaces
Ankara JUG
 
The go-start webframework (GTUG Vienna 27.03.2012)
The go-start webframework (GTUG Vienna 27.03.2012)The go-start webframework (GTUG Vienna 27.03.2012)
The go-start webframework (GTUG Vienna 27.03.2012)ungerik
 
Jquery In Rails
Jquery In RailsJquery In Rails
Jquery In Rails
shen liu
 
AngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsAngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.js
Mark
 
BPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced WorkflowsBPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced Workflows
Alfresco Software
 
Unobtrusive javascript with jQuery
Unobtrusive javascript with jQueryUnobtrusive javascript with jQuery
Unobtrusive javascript with jQueryAngel Ruiz
 
Stack Overflow Austin - jQuery for Developers
Stack Overflow Austin - jQuery for DevelopersStack Overflow Austin - jQuery for Developers
Stack Overflow Austin - jQuery for DevelopersJonathan Sharp
 
SharePoint and jQuery Essentials
SharePoint and jQuery EssentialsSharePoint and jQuery Essentials
SharePoint and jQuery Essentials
Mark Rackley
 
BPM-1 Introduction to Advanced Workflows
BPM-1 Introduction to Advanced WorkflowsBPM-1 Introduction to Advanced Workflows
BPM-1 Introduction to Advanced Workflows
Alfresco Software
 
BPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep DiveBPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep Dive
Alfresco Software
 

What's hot (20)

jQuery: Events, Animation, Ajax
jQuery: Events, Animation, AjaxjQuery: Events, Animation, Ajax
jQuery: Events, Animation, Ajax
 
jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009
 
jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginners
 
Angular JS blog tutorial
Angular JS blog tutorialAngular JS blog tutorial
Angular JS blog tutorial
 
jQuery Presentation
jQuery PresentationjQuery Presentation
jQuery Presentation
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
 
jQuery in the [Aol.] Enterprise
jQuery in the [Aol.] EnterprisejQuery in the [Aol.] Enterprise
jQuery in the [Aol.] Enterprise
 
jQuery Essentials
jQuery EssentialsjQuery Essentials
jQuery Essentials
 
Sane Async Patterns
Sane Async PatternsSane Async Patterns
Sane Async Patterns
 
Jquery Complete Presentation along with Javascript Basics
Jquery Complete Presentation along with Javascript BasicsJquery Complete Presentation along with Javascript Basics
Jquery Complete Presentation along with Javascript Basics
 
AnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFaces
 
The go-start webframework (GTUG Vienna 27.03.2012)
The go-start webframework (GTUG Vienna 27.03.2012)The go-start webframework (GTUG Vienna 27.03.2012)
The go-start webframework (GTUG Vienna 27.03.2012)
 
Jquery In Rails
Jquery In RailsJquery In Rails
Jquery In Rails
 
AngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsAngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.js
 
BPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced WorkflowsBPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced Workflows
 
Unobtrusive javascript with jQuery
Unobtrusive javascript with jQueryUnobtrusive javascript with jQuery
Unobtrusive javascript with jQuery
 
Stack Overflow Austin - jQuery for Developers
Stack Overflow Austin - jQuery for DevelopersStack Overflow Austin - jQuery for Developers
Stack Overflow Austin - jQuery for Developers
 
SharePoint and jQuery Essentials
SharePoint and jQuery EssentialsSharePoint and jQuery Essentials
SharePoint and jQuery Essentials
 
BPM-1 Introduction to Advanced Workflows
BPM-1 Introduction to Advanced WorkflowsBPM-1 Introduction to Advanced Workflows
BPM-1 Introduction to Advanced Workflows
 
BPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep DiveBPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep Dive
 

Similar to Javascript MVC & Backbone Tips & Tricks

Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenery
toddbr
 
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridasFrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
Loiane Groner
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
pootsbook
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
Nick Lee
 
Building a real life application in node js
Building a real life application in node jsBuilding a real life application in node js
Building a real life application in node js
fakedarren
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Francois Zaninotto
 
HTML5 - The 2012 of the Web
HTML5 - The 2012 of the WebHTML5 - The 2012 of the Web
HTML5 - The 2012 of the WebRobert Nyman
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Chris Alfano
 
WordPress as the Backbone(.js)
WordPress as the Backbone(.js)WordPress as the Backbone(.js)
WordPress as the Backbone(.js)
Beau Lebens
 
Introduction to AngularJS
Introduction to AngularJSIntroduction to AngularJS
Introduction to AngularJS
Jussi Pohjolainen
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
Alive Kuo
 
Week 4 - jQuery + Ajax
Week 4 - jQuery + AjaxWeek 4 - jQuery + Ajax
Week 4 - jQuery + Ajaxbaygross
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
jerryorr
 
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
crokitta
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com Backbone
Rafael Felix da Silva
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortal
Jennifer Bourey
 
HTML5 - The 2012 of the Web - Adobe MAX
HTML5 - The 2012 of the Web - Adobe MAXHTML5 - The 2012 of the Web - Adobe MAX
HTML5 - The 2012 of the Web - Adobe MAXRobert Nyman
 
Velocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web appsVelocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web apps
andrewsmatt
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
Skills Matter
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen LjuSkills Matter
 

Similar to Javascript MVC & Backbone Tips & Tricks (20)

Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenery
 
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridasFrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
 
Building a real life application in node js
Building a real life application in node jsBuilding a real life application in node js
Building a real life application in node js
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
HTML5 - The 2012 of the Web
HTML5 - The 2012 of the WebHTML5 - The 2012 of the Web
HTML5 - The 2012 of the Web
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
 
WordPress as the Backbone(.js)
WordPress as the Backbone(.js)WordPress as the Backbone(.js)
WordPress as the Backbone(.js)
 
Introduction to AngularJS
Introduction to AngularJSIntroduction to AngularJS
Introduction to AngularJS
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
Week 4 - jQuery + Ajax
Week 4 - jQuery + AjaxWeek 4 - jQuery + Ajax
Week 4 - jQuery + Ajax
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
 
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com Backbone
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortal
 
HTML5 - The 2012 of the Web - Adobe MAX
HTML5 - The 2012 of the Web - Adobe MAXHTML5 - The 2012 of the Web - Adobe MAX
HTML5 - The 2012 of the Web - Adobe MAX
 
Velocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web appsVelocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web apps
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
 

Recently uploaded

Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
Generating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using SmithyGenerating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using Smithy
g2nightmarescribd
 

Recently uploaded (20)

Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Generating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using SmithyGenerating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using Smithy
 

Javascript MVC & Backbone Tips & Tricks

  • 1. MVC Frameworks in Javascript Hjörtur Hilmarsson @hjortureh
  • 2. Agenda • Why MVC in Javascript ? • Backbone & Spine • Backbone fundamentals • Backbone Tips & Tricks
  • 4. “The world web is changed”
  • 8. Markup <form> ! <!-- Name input --> ! <input id="name" name="name" type="text" placeholder="What is your name?" required /> ! <!-- Email input --> ! <input id="email" name="email" type="email" placeholder="What is your email?" required /> ! <!-- Message input --> ! <textarea id="message" name="message" placeholder="Hello!" required ></textarea> ! <!--Send button --> ! <input id="submit" name="submit" type="submit" value="Send" /> ! <!-- Message label --> ! <span id="message" ></span> </form>
  • 9. Javascript - Old style $("form").submit(function( e ) { ! ! ! ! ! e.preventDefault(); ! // get values var $form = $(this); var data = { name: $form.find("[name=name]").val(), email: $form.find("[name=email]").val(), message: $form.find("[name=message]").val() }; // ajax request $.ajax({ type: "post", url: "/enquiry", contentType: "application/json", dataType: "json", data: data, success: function() { $form.find("#message").text("Message posted").fadeIn(); }, error: function() { $form.find("#message").text("Sorry, there was an error").fadeIn(); } }); });
  • 10. Controller - MVC style $("form").submit(function( e ) { ! ! ! ! ! e.preventDefault(); ! // get values ! var $form = $(this); ! var data = { ! ! name: $form.find("[name=name]").val(), ! ! email: $form.find("[name=email]").val(), ! ! message: $form.find("[name=message]").val() ! }; ! // model ! var enquiry = new Enquiry( data ); ! ! enquiry.save( ! ! function() { ! ! ! $form.find("#message").text("Message posted"); ! ! }, ! ! function() { ! ! ! $form.find("#message").text("Sorry, there was an error"); ! ! } ! ); });
  • 11. Model - MVC style // constructor var Enquiry = function( data ) { ! this.data = data; }; // save method Enquiry.prototype.save = function( success, error ) { ! // ajax request ! $.ajax({ ! ! type: "post", ! ! url: "/enquiry", ! ! contentType: "application/json", ! ! dataType: "json", ! ! data: this.data, ! ! success: success, ! ! error: error ! }); };
  • 12. Backbone.js controller view var ContactUs = Backbone.View.extend({ ! ! // local variables ! el: $("form").get(0), ! events: { "submit": "submit" } ! model: new Enquiry, ! // constructor ! initialize: function() { ! ! this.model.bind("create", create, this );! ! ! this.model.bind("error", error, this );! ! }, ! // submit event ! submit: function( e ) { ! ! e.preventDefault(); ! ! ! ! var data = { ! ! ! name: this.$("[name=name]").val(), ! ! ! email: this.$("[name=email]").val(), ! ! ! message: this.$("[name=message]").val() ! ! }; ! ! this.model.save(); ! }, ! // success callback ! create: function() { ! ! this.$("#message").text("Message posted"); ! }, ! // error callback ! error: function() { ! ! this.$("#message").text("Sorry, there was an error"); ! } });
  • 13. Backbone.js model var Enquiry = Backbone.Model.extend({});
  • 14.
  • 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
  • 21. • Created 2010 by Jeremy Ashkenas • File size 5.4k • Depends on Underscore.js ( 4k ) • Very popular
  • 23.
  • 25. Spine • Inspired by Backbone • Written in CoffeeScript by Alex McCaw • File size 7k • Introduced async UI concept
  • 28. Modules • Events • Models • Collections • Views • Routes • History
  • 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 ); });
  • 33. Models • Wrapper for JSON & syncing via JSON • RESTful by default. Overwrite sync method to change persistence logic. • Communicates via events ( create, change, destroy, sync, error, add , remove ) • Can handle validation
  • 34. Model var Todo = Backbone.Model.extend({ defaults: { done: false }, toggle: function() { this.save({done: !this.get("done")}); }, clear: function() { this.destroy(); } });
  • 35. TodoMVC - example http://addyosmani.github.com/todomvc/architecture-examples/backbone/index.html
  • 37. Collections • List of models • Fires events for collection and the models • Keeps models sorted • Includes many utility methods
  • 38. Collection var TodoList = Backbone.Collection.extend({ model: Todo, done: function() { return this.filter(function(todo){ return todo.get('done'); }); }, remaining: function() { return this.without.apply(this, this.done() ); }, comparator: function(todo) { return todo.get('order'); } });
  • 39. Views
  • 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
  • 41. Organizing views 1:1 View Model
  • 42. Todo view var TodoView = Backbone.View.extend({ tagName: "li", template: _.template($('#item-template').html()), events: { "click .check" : "toggleDone" }, initialize: function() { _.bindAll(this, 'render' ); this.model.bind('change', this.render ); }, render: function() { $(this.el).html(this.template(this.model.toJSON())); return this; }, toggleDone: function() { this.model.toggle(); } ... }
  • 43. Template <script type="text/template" id="item-template"> <div class="todo <%= done ? 'done' : '' %>"> <div class="display"> <input class="check" type="checkbox" <%= done ? 'checked="checked"' : '' %> /> <label class="todo-content"><%= content %></label> <span class="todo-destroy"></span> </div> <div class="edit"> <input class="todo-input" type="text" value="<%= content %>" /> </div> </div> </script>
  • 44. App view var AppView = Backbone.View.extend({ ! el: $("#todoapp"), ! ! initialize: function() { ! ! _.bindAll(this, 'addOne', 'addAll', 'render' ); ! ! Todos.on('add', this.addOne); ! ! Todos.on('reset', this.addAll); ! ! Todos.fetch(); ! }, ! addOne: function(todo) { ! ! var view = new TodoView({model: todo}); ! ! this.$("#todo-list").append(view.render().el); ! }, ! addAll: function() { ! ! Todos.each(this.addOne); ! } ! ... }
  • 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
  • 48. Router APP.Router = Backbone.Router.extend({ routes: { "new": "newNote", ":id": "editNote", "": "home" }, home: function() { APP.appView.home(); }, newNote: function() { APP.appView.newNote(); }, editNote: function( id ) { APP.appView.editNote( id ); } });
  • 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});
  • 50. Demo
  • 51. Backbone tips & tricks
  • 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" } ]);
  • 56. Demo
  • 58. Tip #2 Async User Interfaces
  • 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 !
  • 62. Demo
  • 64. Question Has many Answers
  • 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
  • 66. Nested models var Question = Backbone.Model.extend({ initialize: function() { // collection instance this.answers = new Answers; }, parse: function(resp, xhr) { // fill nested model if( _.isArray( resp.answers ) ) { this.answers.reset( resp.answers ); } return resp; }, toJSON: function() { // send nested models return $.extend( this.attributes(), { answers: this.answers.toJSON() } ); } });
  • 67. Tip #4 Custom ajax requests
  • 68. Custom ajax request • Sometimes RESTful methods are not enough • Example: Sorting tasks in to-do list
  • 69.
  • 70. Sorting - Custom request saveOrder: function() { ! ! var ids = this.pluck("id"); ! ! window.$.ajax({ ! ! url: "/tasks/reorder", ! ! data: { ! ! ! ids: ids ! ! }, ! ! type: "POST", ! ! dataType: "json", ! ! complete: function() { ! ! ! // Handle response ! ! } ! }); ! }
  • 71. Tip #5 Send zombies to heaven
  • 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();
  • 74. Tip #6 Use the toolbox
  • 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(); });
  • 80. Demo
  • 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
  • 87. Bonus points • Read the documentation • Read the source code • Just do it !
  • 88. Tack så mycket Hjörtur Elvar Hilmarsson @hjortureh