Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AngularJS vs. Ember.js vs. Backbone.js

Kod.io
October 26, 2013

AngularJS vs. Ember.js vs. Backbone.js

By Mark Bates
http://kod.io

Kod.io

October 26, 2013
Tweet

More Decks by Kod.io

Other Decks in Programming

Transcript

  1. @markbates

  2. hire me* (for rent, not sale)

  3. None
  4. None
  5. None
  6. KODIO13 www.metacasts.tv

  7. AngularJS vs. Ember vs. Backbone.js

  8. Knockout.js

  9. philosophies

  10. Backbone.js “minimal set of data-structure and view primitives for building

    web application with JavaScript”
  11. Backbone.js do what you want, however you want to do

    it (we won’t tell anyone)
  12. Ember “framework for creating ambitious web applications”

  13. Ember convention over configuration

  14. AngularJS “Toolset for building the framework most suited to your

    application development”
  15. AngularJS plain old JavaScript

  16. None
  17. None
  18. None
  19. Round 1

  20. weight

  21. “production” versions (minified) w/ required dependencies

  22. AngularJS Ember Backbone.js base 81kb 235kb 6.4kb templating language built-in

    73kb (handlebars) ?? data adapter built-in 210kb (ember-data) 32kb (jQuery) support N/A 32kb (jQuery) 17kb (json2.js) 4.9kb (underscore.js) 81kb 550kb 60.3kb
  23. Round 2

  24. “basic” models

  25. Backbone.js class  App.Beer  extends  Backbone.Model       class  App.Beers

     extends  Backbone.Collection   !  model:  Beer
  26. Ember App.Beer  =  DS.Model.extend      title:  DS.attr("string")    

     abv:  DS.attr("number")      country_id:  DS.attr("number")      brewery_id:  DS.attr("number")      brewery:  DS.belongsTo("App.Brewery")      country:  DS.belongsTo("App.Country")
  27. AngularJS App.Beer  =  {}

  28. “remote” models

  29. Backbone.js class  App.Beer  extends  Backbone.Model      urlRoot:  "/api/v1/beers"  

          class  App.Beers  extends  Backbone.Collection          url:  -­‐>          if  @brewery_id?              return  "/api/v1/breweries/#{@brewery_id}/beers"          else              return  "/api/v1/beers"          model:  Beer
  30. Ember App.Beer  =  DS.Model.extend      title:  DS.attr("string")    

     abv:  DS.attr("number")      country_id:  DS.attr("number")      brewery_id:  DS.attr("number")      brewery:  DS.belongsTo("App.Brewery")      country:  DS.belongsTo("App.Country")
  31. Ember DS.RESTAdapter.reopen      namespace:  'api/v1'       App.Store

     =  DS.Store.extend      revision:  11      adapter:  DS.RESTAdapter.create()
  32. AngularJS App.factory  "Beer",  ($resource)  -­‐>      return  $resource  "/api/v1/beers/:id",

                                           {id:  "@id"},                                        {update:  {method:  "PUT"}}
  33. Round 3

  34. routers

  35. Backbone.js @Router  =  Backbone.Router.extend          initialize:  -­‐>

             @countries  =  new  Countries()          routes:          "breweries/:brewery_id":  "brewery"          "breweries/:brewery_id/edit":  "breweryEdit"          brewery:  (brewery_id)  -­‐>          @changeView(new  BreweryView(collection:  @countries,  model:  new  Brewery(id:  brewery_id)))          breweryEdit:  (brewery_id)  -­‐>          @changeView(new  BreweryEditView(collection:  @countries,  model:  new  Brewery(id:  brewery_id)))          changeView:  (view)  =>          @currentView?.remove()          @currentView  =  view          $("#outlet").html(@currentView.el)
  36. Ember App.Router.map  -­‐>      @resource  "brewery",  {path:  "brewery/:brewery_id"}

  37. Ember App.BreweryRoute  =  Ember.Route.extend      model:  (params)-­‐>    

         App.Brewery.find(params.brewery_id)
  38. AngularJS App.config  ($routeProvider)  -­‐>          $routeProvider  

           .when("/breweries/:id",  {              templateUrl:  "/assets/brewery.html",              controller:  "BreweryController"          })          .when("/breweries/:id/edit",  {              templateUrl:  "/assets/edit_brewery.html",              controller:  "EditBreweryController"          })
  39. Round 4

  40. controllers/views

  41. Backbone.js class  @BreweryEditView  extends  Backbone.View          template:

     "brewery_edit"          events:          "click  #save-­‐button":  "saveClicked"          "keypress  #brewery-­‐title":  "titleEdited"          initialize:  -­‐>          super          @countriesView  =  new  CountriesView(collection:  @collection)          @$el.html(@countriesView.el)          @model.on  "change",  @render          @model.fetch()          render:  =>          @$("#country-­‐outlet").html(@renderTemplate())          return  @    saveClicked:  (e)  =>          e?.preventDefault()          attrs  =              title:  @$("#brewery-­‐title").val()              synonyms:  @$("#brewery-­‐synonyms").val()              address:  @$("#brewery-­‐address").val()          @model.save  attrs,              success:  (model,  response,  options)  =>                  App.navigate("/breweries/#{@model.id}",  trigger:  true)              error:  (model,  xhr,  options)  -­‐>                  errors  =  []                  for  key,  value  of  xhr.responseJSON.errors                      errors.push  "#{key}:  #{value.join(",  ")}"                  alert  errors.join("\n")          titleEdited:  (e)  =>          title  =  @$("#brewery-­‐title").val()          @$("h2").text(title)   !    #  further  code  omitted
  42. Ember App.BreweryController  =  Ember.ObjectController.extend        save:  -­‐>  

           @store.commit()          #  further  code  omitted
  43. AngularJS @EditBreweryController  =  ($scope,  $routeParams,  $location,  Brewery)  -­‐>    

         $scope.brewery  =  Brewery.get(id:  $routeParams.id)          $scope.save  =  -­‐>          success  =  -­‐>              $location.path("/breweries/#{$routeParams.id}")              $scope.errors  =  null          failure  =  (object)-­‐>              $scope.errors  =  object.data.errors          $scope.brewery.$update  {},  success,  failure
  44. Round 5

  45. templates

  46. Backbone.js <h2><%=  @model.displayName()  %></h2>       <form>    

         <div  class="control-­‐group">          <label  class="control-­‐label"  for="title">Title</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("title")  %>'id='brewery-­‐title'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="synonyms">Synonyms</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("synonyms")  %>'id='brewery-­‐synonyms'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="address">Address</label>          <div  class="controls">              <textarea  class='input-­‐xxlarge'  id='brewery-­‐address'><%=  @model.get("address")  %></textarea>          </div>      </div>          <button  class='btn  btn-­‐primary'  id='save-­‐button'>Save</button>      <a  href="/breweries/<%=  @model.id  %>"  class='btn'>Cancel</a>       </form>
  47. Backbone.js <h2><%=  @model.displayName()  %></h2>       <form>    

         <div  class="control-­‐group">          <label  class="control-­‐label"  for="title">Title</label>          <div  class="controls">               <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("title")   %>'id='brewery-­‐title'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="synonyms">Synonyms</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("synonyms")  %>'id='brewery-­‐synonyms'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="address">Address</label>          <div  class="controls">              <textarea  class='input-­‐xxlarge'  id='brewery-­‐address'><%=  @model.get("address")  %></textarea>          </div>      </div>          <button  class='btn  btn-­‐primary'  id='save-­‐button'>Save</button>      <a  href="/breweries/<%=  @model.id  %>"  class='btn'>Cancel</a>       </form>             <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("title")   %>'id='brewery-­‐title'>
  48. Backbone.js <h2><%=  @model.displayName()  %></h2>       <form>    

         <div  class="control-­‐group">          <label  class="control-­‐label"  for="title">Title</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("title")  %>'id='brewery-­‐title'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="synonyms">Synonyms</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  value='<%=  @model.get("synonyms")  %>'id='brewery-­‐synonyms'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="address">Address</label>          <div  class="controls">               <textarea  class='input-­‐xxlarge'  id='brewery-­‐address'><%=  @model.get("address")   %></textarea>          </div>      </div>          <button  class='btn  btn-­‐primary'  id='save-­‐button'>Save</button>      <a  href="/breweries/<%=  @model.id  %>"  class='btn'>Cancel</a>       </form>             <textarea  class='input-­‐xxlarge'  id='brewery-­‐address'><%=  @model.get("address")   %></textarea>
  49. <div  class='span12'>      <h2>{{displayName}}</h2>      <h3>    

         {{cityState}}          {{#linkTo  "country"  country}}              {{country.title}}          {{/linkTo}}      </h3>      {{#if  isEditing}}          <form>                  <div  class="control-­‐group">                  <label  class="control-­‐label"  for="title">Title</label>                  <div  class="controls">                      {{view  Ember.TextField  valueBinding="title"  class='input-­‐xxlarge'}}                  </div>              </div>                  <div  class="control-­‐group">                  <label  class="control-­‐label"  for="synonyms">Synonyms</label>                  <div  class="controls">                      {{view  Ember.TextField  valueBinding="synonyms"  class='input-­‐xxlarge'}}                  </div>              </div>                  <div  class="control-­‐group">                  <label  class="control-­‐label"  for="synonyms">Synonyms</label>                  <div  class="controls">                      {{view  Ember.TextArea  valueBinding="address"  class='input-­‐xxlarge'}}                  </div>              </div>                  <button  class='btn  btn-­‐primary'  {{action  "save"}}>Save</button>              </form>      {{  else  }}          {{  partial  "brewery/show"  }}      {{/if}}   </div> Ember
  50. <div  class='span12'>      <h2>{{displayName}}</h2>      <h3>    

         {{cityState}}          {{#linkTo  "country"  country}}              {{country.title}}          {{/linkTo}}      </h3>      {{#if  isEditing}}          <form>                  <div  class="control-­‐group">                  <label  class="control-­‐label"  for="title">Title</label>                  <div  class="controls">                       {{view  Ember.TextField  valueBinding="title"  class='input-­‐xxlarge'}}                  </div>              </div>                  <div  class="control-­‐group">                  <label  class="control-­‐label"  for="synonyms">Synonyms</label>                  <div  class="controls">                      {{view  Ember.TextField  valueBinding="synonyms"  class='input-­‐xxlarge'}}                  </div>              </div>                  <div  class="control-­‐group">                  <label  class="control-­‐label"  for="synonyms">Synonyms</label>                  <div  class="controls">                      {{view  Ember.TextArea  valueBinding="address"  class='input-­‐xxlarge'}}                  </div>              </div>                  <button  class='btn  btn-­‐primary'  {{action  "save"}}>Save</button>              </form>      {{  else  }}          {{  partial  "brewery/show"  }}      {{/if}}   </div> Ember                     {{view  Ember.TextField  valueBinding="title"  class='input-­‐xxlarge'}}
  51. <div  class='span12'>      <h2>{{displayName}}</h2>      <h3>    

         {{cityState}}          {{#linkTo  "country"  country}}              {{country.title}}          {{/linkTo}}      </h3>      {{#if  isEditing}}          <form>                  <div  class="control-­‐group">                  <label  class="control-­‐label"  for="title">Title</label>                  <div  class="controls">                      {{view  Ember.TextField  valueBinding="title"  class='input-­‐xxlarge'}}                  </div>              </div>                  <div  class="control-­‐group">                  <label  class="control-­‐label"  for="synonyms">Synonyms</label>                  <div  class="controls">                      {{view  Ember.TextField  valueBinding="synonyms"  class='input-­‐xxlarge'}}                  </div>              </div>                  <div  class="control-­‐group">                  <label  class="control-­‐label"  for="synonyms">Synonyms</label>                  <div  class="controls">                      {{view  Ember.TextArea  valueBinding="address"  class='input-­‐xxlarge'}}                  </div>              </div>                   <button  class='btn  btn-­‐primary'  {{action  "save"}}>Save</button>              </form>      {{  else  }}          {{  partial  "brewery/show"  }}      {{/if}}   </div> Ember             <button  class='btn  btn-­‐primary'  {{action  "save"}}>Save</button>
  52. <form>      <h3>{{brewery.title}}</h3>      <div  ng-­‐include='"/assets/_errors.html"'></div>    

     <div  class="control-­‐group">          <label  class="control-­‐label"  for="title">Title</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.title'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="synonyms">Synonyms</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.synonyms'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="address">Address</label>          <div  class="controls">              <textarea  class='input-­‐xxlarge'  ng-­‐model='brewery.address'></textarea>          </div>      </div>          <button  class='btn  btn-­‐primary'  ng-­‐click='save()'>Save</button>       </form> AngularJS
  53. AngularJS <form>      <h3>{{brewery.title}}</h3>      <div  ng-­‐include='"/assets/_errors.html"'></div>  

       <div  class="control-­‐group">          <label  class="control-­‐label"  for="title">Title</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.title'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="synonyms">Synonyms</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.synonyms'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="address">Address</label>          <div  class="controls">              <textarea  class='input-­‐xxlarge'  ng-­‐model='brewery.address'></textarea>          </div>      </div>          <button  class='btn  btn-­‐primary'  ng-­‐click='save()'>Save</button>       </form>            <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.title'>
  54. <form>      <h3>{{brewery.title}}</h3>      <div  ng-­‐include='"/assets/_errors.html"'></div>    

     <div  class="control-­‐group">          <label  class="control-­‐label"  for="title">Title</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.title'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="synonyms">Synonyms</label>          <div  class="controls">              <input  type='text'  class='input-­‐xxlarge'  ng-­‐model='brewery.synonyms'>          </div>      </div>          <div  class="control-­‐group">          <label  class="control-­‐label"  for="address">Address</label>          <div  class="controls">              <textarea  class='input-­‐xxlarge'  ng-­‐model='brewery.address'></textarea>          </div>      </div>          <button  class='btn  btn-­‐primary'  ng-­‐click='save()'>Save</button>       </form> AngularJS    <button  class='btn  btn-­‐primary'  ng-­‐click='save()'>Save</button>
  55. Round 6

  56. pros/cons

  57. Backbone.js • Too simple • Not opinionated enough • “Memory”

    management • Unstructured • Spaghetti code • Lightweight • Not opinionated • Simple • Easy to read source • “widget” development Pros Cons
  58. Ember • Too complex • Overly opinionated • Heavyweight •

    ember-data - not production ready • API always in flux • Buggy • Little to no mind-share outside of Rails • Difficult to read source code • Structured • Highly opinionated • “less” code • “large” apps Pros Cons
  59. AngularJS • Difficult to read source code • jQuery plugins

    require custom directives • Large apps requiring self-imposed structure • Lightly structured • Lightly opinionated • “less” code • Plain JavaScript • Simple/Powerful • Easy to test • Lightweight • small, medium, or large apps Pros Cons
  60. Summary

  61. think before you choose

  62. don’t cargo cult

  63. don’t use Backbone.js!

  64. play with them all

  65. watch the metacasts.tv episodes on them ;)

  66. @markbates http://www.metacasts.tv