AngularJS vs. Ember.js vs. Backbone.js
-
Upload
mark -
Category
Technology
-
view
1.362 -
download
2
description
Transcript of AngularJS vs. Ember.js vs. Backbone.js
@markbates
hire me* (for rent, not sale)
KODIO13www.metacasts.tv
AngularJS vs. Ember vs. Backbone.js
Knockout.js
philosophies
Backbone.js
“minimal set of data-structure and view primitives for building web application with JavaScript”
Backbone.js
do what you want, however you want to do it
(we won’t tell anyone)
Ember
“framework for creating ambitious web applications”
Ember
convention over configuration
AngularJS
“Toolset for building the framework most suited to your application development”
AngularJS
plain old JavaScript
Round 1
weight
“production” versions (minified) w/ required dependencies
AngularJS Ember Backbone.js
base 81kb 235kb 6.4kb
templating language built-in73kb
(handlebars) ??
data adapter built-in210kb
(ember-data)32kb
(jQuery)
support N/A32kb
(jQuery)
17kb (json2.js)
4.9kb (underscore.js)
81kb 550kb 60.3kb
Round 2
“basic” models
Backbone.js
class App.Beer extends Backbone.Model class App.Beers extends Backbone.Collection !
model: Beer
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")
AngularJS
App.Beer = {}
“remote” models
Backbone.jsclass 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
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")
EmberDS.RESTAdapter.reopen namespace: 'api/v1' App.Store = DS.Store.extend revision: 11 adapter: DS.RESTAdapter.create()
AngularJS
App.factory "Beer", ($resource) -‐> return $resource "/api/v1/beers/:id", {id: "@id"}, {update: {method: "PUT"}}
Round 3
routers
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)
Ember
App.Router.map -‐> @resource "brewery", {path: "brewery/:brewery_id"}
Ember
App.BreweryRoute = Ember.Route.extend model: (params)-‐> App.Brewery.find(params.brewery_id)
AngularJSApp.config ($routeProvider) -‐> $routeProvider .when("/breweries/:id", { templateUrl: "/assets/brewery.html", controller: "BreweryController" }) .when("/breweries/:id/edit", { templateUrl: "/assets/edit_brewery.html", controller: "EditBreweryController" })
Round 4
controllers/views
Backbone.jsclass @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
Ember
App.BreweryController = Ember.ObjectController.extend save: -‐> @store.commit() # further code omitted
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
Round 5
templates
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>
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'>
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>
<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
<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'}}
<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>
<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
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'>
<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>
Round 6
pros/cons
Backbone.js
• Too simple
• Not opinionated enough
• “Memory” management
• Unstructured
• Spaghetti code
• Lightweight
• Not opinionated
• Simple
• Easy to read source
• “widget” development
Pros Cons
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
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
Summary
think before you choose
don’t cargo cult
don’t use Backbone.js!
play with them all
watch the metacasts.tv episodes on them ;)
@markbates http://www.metacasts.tv