SlideShare uma empresa Scribd logo
1 de 88
Baixar para ler offline
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

Mais conteúdo relacionado

Mais procurados

jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009Remy Sharp
 
Angular JS blog tutorial
Angular JS blog tutorialAngular JS blog tutorial
Angular JS blog tutorialClaude Tech
 
jQuery Presentation
jQuery PresentationjQuery Presentation
jQuery PresentationRod 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 Widgetsvelveeta_512
 
jQuery in the [Aol.] Enterprise
jQuery in the [Aol.] EnterprisejQuery in the [Aol.] Enterprise
jQuery in the [Aol.] EnterpriseDave Artz
 
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 BasicsEPAM Systems
 
AnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkara 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 Railsshen 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.jsMark
 
BPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced WorkflowsBPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced WorkflowsAlfresco 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 EssentialsMark Rackley
 
BPM-1 Introduction to Advanced Workflows
BPM-1 Introduction to Advanced WorkflowsBPM-1 Introduction to Advanced Workflows
BPM-1 Introduction to Advanced WorkflowsAlfresco Software
 
BPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep DiveBPM-3 Advanced Workflow Deep Dive
BPM-3 Advanced Workflow Deep DiveAlfresco Software
 

Mais procurados (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
 

Semelhante a Javascript MVC & Backbone Tips & Tricks

Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenerytoddbr
 
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íbridasLoiane 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 MVCpootsbook
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejsNick 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 jsfakedarren
 
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 jsFrancois 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
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive 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 modulesjerryorr
 
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 2012crokitta
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneRafael Felix da Silva
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortalJennifer 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 appsandrewsmatt
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen LjuSkills Matter
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen LjuSkills Matter
 

Semelhante a 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
 

Último

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 

Último (20)

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 

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