SlideShare a Scribd company logo
Single Page Web
    Applications
CoffeeScript + Backbone.js + Jasmine BDD



             @pirelenito
        github.com/pirelenito
              #tdc2011
Who am I?
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
What can you expect?

• What I am doing?
• Why is CoffeeScript so awesome?
• The era before Backbone;
• Fix browser spaghetti code with Backbone;
• Be professional: with Jasmine BDD;
Assumptions

• You know your Javascript;
• and your JQuery;
• You developed for the web before.
What I am doing?
Fullscreen Map
Geo CRUDs
No refreshes
Fullscreen Map
Geo CRUDs
No refreshes




CoffeeScript
Backbone.js
Fullscreen Map
            Geo CRUDs
            No refreshes




            CoffeeScript
            Backbone.js
     JSON

Rest API    Ruby on Rails
Why is CoffeeScript so
      awesome?
I like to choose my
        tools!
I can to that on the
       Server!
Browser?
Javascript Only!
Browser?
Javascript Only!
NO MOAR!
Too error-prone.
Semicolon insertion

return     return {
{             a: 10
   a: 10   };
};
Semicolon insertion

return ;   return {
{             a: 10
   a: 10   };
};
Global variables
function messWithGlobal() {
  a = 10;
}
Global variables
function messWithGlobal() {
  a = 10;
}

messWithGlobal();
alert(a);
Global variables
function messWithGlobal() {
  a = 10;
}

messWithGlobal();
alert(a);
Global variables
function messWithGlobal() {
  a = 10;
}

messWithGlobal();
alert(a);


function messWithGlobal() {
  var a = 10;
}
}
  square = function(x) {
     return x * x;
  };
  list = [1, 2, 3, 4, 5];
  math = {
     root: Math.sqrt,   Too verbose!
     square: square,
     cube: function(x) {
       return x * square(x);
     }
  };
  race = function() {
     var runners, winner;
     winner = arguments[0], runners = 2 <=
arguments.length ? __slice.call(arguments,
1) : [];
     return print(winner, runners);
  };
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Awesome platform.
“I Think Coffeescript is
   clearly good stuff”
                       Douglas Crockford




             Javascript Programming Style And Your Brain
Remember this?
return     return {
{             a: 10
   a: 10   };
};
Coffeescript:
return       return a: 10
  a: 10
Coffeescript:
return       return a: 10
  a: 10




  It has no semicolon!
How it fixes globals?
Never write var again!

 messWithGlobal = ->
   a = 10
Never write var again!

 messWithGlobal = ->
   a = 10



messWithGlobal = function() {
   var a;
   return a = 10;
};
Compiles with scope

a = 10
Compiles with scope

a = 10




(function() {
  var a;
  a = 10;
}).call(this);
You want global?
           Go explicit!
window.messWithGlobal = ->
  a = 10
You want global?
           Go explicit!
window.messWithGlobal = ->
  a = 10


(function() {
  window.messWithGlobal = function() {
     var a;
     return a = 10;
  };
}).call(this);
Functions as callbacks
$('.button').click(function() {
  return alert('clicked!');
});
Functions as callbacks
$('.button').click(function() {
  return alert('clicked!');
});




$('.button').click -> alert 'clicked!'
Block by identation
 if (somethingIsTrue) {
   complexMath = 10 * 3;
 }
Block by identation
 if (somethingIsTrue) {
   complexMath = 10 * 3;
 }



 if somethingIsTrue
   complexMath = 10 * 3
Classes
class MyClass
  attribute: 'value'
  constructor: ->
    @objectVariable = 'Dude'

  myMethod: ->
    # this.objectVariable
    @objectVariable
Classes
class MyClass
  attribute: 'value'
  constructor: ->
    @objectVariable = 'Dude'

  myMethod: ->
    # this.objectVariable
    @objectVariable

object = new MyClass
object.myMethod()
object.objectVariable # Dude
object.attribute
Compiled class:
(function() {
  var MyClass;
  MyClass = (function() {
    MyClass.prototype.attribute = 'value';
    function MyClass() {
       this.objectVariable = 'Dude';
    }
    MyClass.prototype.myMethod = function() {
       return this.objectVariable;
    };
    return MyClass;
  })();
}).call(this);
Ranges
list = [1..5]
Ranges
list = [1..5]




var list;
list = [1, 2, 3, 4, 5];
Expressions!
vehicles = for i in [1..3]
  "Vehicle#{i}"
Expressions!
vehicles = for i in [1..3]
  "Vehicle#{i}"


vehicles
['Vehicle1', 'Vehicle2', 'Vehicle3']
More awesomeness...
number = -42 if opposite

math =
  square:   (x) -> x * x

race = (winner, runners...) ->
  print winner, runners

alert "I knew it!" if elvis?

squares = (math.square num for num in list)
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Don’t use --bare
Namespaces are cool
class namespace('views').MyView
Namespaces are cool
class namespace('views').MyView



new oncast.views.MyView()
Namespaces are cool
class namespace('views').MyView



new oncast.views.MyView()



@.namespace = (name) ->
  @.oncast ||= {}
  return @.oncast[name] ||= {} if name
  return @.oncast
No more hidden bugs
 on my client code!
CoffeeScript will make
you a better Javascript
     programer.
The era before
  Backbone.
Rails did the rendering
           Rails




        Coffeescript
Rails did the rendering
                           Rails




$('.new').load "/cars/new", prepare




                       Coffeescript
Rails did the rendering
                           Rails




$('.new').load "/cars/new", prepare




                       Coffeescript
Rails did the rendering
                           Rails
                                      <form>
                                        <input name='name'>
                                        ...
                                      </form>


$('.new').load "/cars/new", prepare




                       Coffeescript
Rails did the rendering
                           Rails
                                      <form>
                                        <input name='name'>
                                        ...
                                      </form>


$('.new').load "/cars/new", prepare




                       Coffeescript
Advantages

• Simple;
• Used tools we knew;
• i18n.
Coffeescript Actions

ActionActivationHandler    One active at time




EditRefAction         ListRefAction      ...
Mapped an action on
our Rail’s Controller
Action Abstraction

• Would handle the ‘remote’ rendering;
• Initialize the rich components on the
  DOM;
• JQuery heavy.
Problems?
One Action at a time!
Difficult to keep thinks
        in sync.
Difficult to keep thinks
        in sync.
   No real state on the browser.
Slow (web 1.0)
“Not surprisingly, we're finding
  ourselves solving similar
   problems repeatedly.”
                                                          Henrik Joreteg



http://andyet.net/blog/2010/oct/29/building-a-single-page-app-with-backbonejs-undersc/
Fix browser spaghetti
code with Backbone.
Why Backbone?
Gives enough structure
Very lightweight
Easy to get started!
Why not GWT(for instance)?
Doesn’t hide the DOM
 You are doing real web development.
Works nicely with
 CoffeeScript
  Inheritance.

 https://github.com/documentcloud/backbone/blob/master/test/model.coffee
Works nicely with
  CoffeeScript
   Inheritance.
class Car extends Backbone.Model


    https://github.com/documentcloud/backbone/blob/master/test/model.coffee
Ok, but what is it?
Four Abstractions

• Collection;
• Model;
• Router;
• View;
Models / Collections
class Reference extends Backbone.Model
  urlRoot: "/references"
Models / Collections
class Reference extends Backbone.Model
  urlRoot: "/references"


class References extends Backbone.Collection
  model: Reference
  url: '/references'



        Model   Model   Model
                                Collection
Fetch Collection
# creates a new collection
references = new References

# fetch data asynchronously
references.fetch()
Fetch Collection
# creates a new collection
references = new References

# fetch data asynchronously
references.fetch()


               [{
                   id: 1
      JSON         name: "Paulo's House",
                   latitude: '10',
                   longitude: '15'
                 }]
Model attributes
Model attributes
# get reference with id 1
reference = references.get 1
Model attributes
# get reference with id 1
reference = references.get 1

# get the name property of the model
name = reference.get 'name'
Model attributes
# get reference with id 1
reference = references.get 1

# get the name property of the model
name = reference.get 'name'

# change the name property of the model
reference.set name: 'new name'
Model attributes
# get reference with id 1
reference = references.get 1

# get the name property of the model
name = reference.get 'name'

# change the name property of the model
reference.set name: 'new name'

# save the model to the server
reference.save()
Why use model.set ?
reference.set name: 'new name'
Events!
reference.bind 'change', (name)-> alert name
Events!
reference.bind 'change', (name)-> alert name

reference.set name: 'new name'
Events!
reference.bind 'change', (name)-> alert name

reference.set name: 'new name'
Views
class SaveButtonView extends Backbone.View
  className: 'save-button'
  tagName: 'div'
  events:
    click: '_click'

  render: ->
    $(@el).html "<input type='button'
                 value='Save'></input>"
    return @

  _click: ->
    @model.save()
Views
class SaveButtonView extends Backbone.View
  className: 'save-button'
  tagName: 'div'
  events:
    click: '_click'

  render: ->
    $(@el).html "<input type='button'
                 value='Save'></input>"
    return @

  _click: ->
    @model.save()
Views
class SaveButtonView extends Backbone.View
  className: 'save-button'
  tagName: 'div'
  events:
    click: '_click'

  render: ->
    $(@el).html "<input type='button'
                 value='Save'></input>"
    return @

  _click: ->
    @model.save()
Views
class SaveButtonView extends Backbone.View
  className: 'save-button'
  tagName: 'div'
  events:
    click: '_click'

  render: ->
    $(@el).html "<input type='button'
                 value='Save'></input>"
    return @

  _click: ->
    @model.save()
Views
class SaveButtonView extends Backbone.View
  className: 'save-button'
  tagName: 'div'
  events:
    click: '_click'

  render: ->
    $(@el).html "<input type='button'
                 value='Save'></input>"
    return @

  _click: ->
    @model.save()
Views
class SaveButtonView extends Backbone.View
  className: 'save-button'
  tagName: 'div'
  events:
    click: '_click'

  render: ->
    $(@el).html "<input type='button'
                 value='Save'></input>"
    return @

  _click: ->
    @model.save()
Using a View
Using a View
# creates a new instance of the view
view = new SaveButtonView()
Using a View
# creates a new instance of the view
view = new SaveButtonView()

# render it
view.render()
Using a View
# creates a new instance of the view
view = new SaveButtonView()

# render it
view.render()

# append the content of the view on the doc
$('.some-div').html view.el
‘Events’ is the magic
     element!
‘Events’ is the magic
     element!
   They will keep you in sync!
View   Model
Click!




View     Model
Click!

         event changes the model


View                               Model
Click!           model.set name: 'new name'


         event changes the model


View                               Model
Click!           model.set name: 'new name'


         event changes the model


View                               Model
         event changes the view
Click!               model.set name: 'new name'


            event changes the model


View                                  Model
             event changes the view




         keeps everything in sync
Routers
class ReferencesRouter extends Backbone.Router
  routes:
    'references': 'index'

  initialize: (options)->
    @listPanelView = options.listPanelView

  index: ->
    @listPanelView.renderReferences()
Routers
class ReferencesRouter extends Backbone.Router
  routes:
    'references': 'index'

  initialize: (options)->
    @listPanelView = options.listPanelView

  index: ->
    @listPanelView.renderReferences()
Routers
class ReferencesRouter extends Backbone.Router
  routes:
    'references': 'index'

  initialize: (options)->
    @listPanelView = options.listPanelView

  index: ->
    @listPanelView.renderReferences()
This is just the basics!
Lessons Learned
DOM is not always
  your friend!
DOM is not always
         your friend!
# will be 0 unless it is attached to the
# document
$(@el).height()
Always do
       view.render()




        Before
$('.some-div').html view.el
Always return this.
Always return this.
new SaveButtonView().highlight().render().el
Routers should only
      route!
Routers should only
         route!
index: ->
  @listPanelView.renderReferences()
You don’t need an
Action abstraction!!!
The View will represent
 one model/collection
       forever!
Broken events
# append the view's element to the document
$('.div').append view.el

# remove it
$('.div').empty

# add it again
$('.div').append view.el

   View events (click, change) will no longer work.
Collection.getOrFetch
class Posts extends Backbone.Collection
  url: "/posts"

  getOrFetch: (id) ->
    if @get(id)
      post = @get id
    else
      post = new Post { id : id }
      @add post
      post.fetch()

   post
             http://bennolan.com/2011/06/10/backbone-get-or-fetch.html
View.fetch
Backbone.View::fetch = (options={})->
  return @ unless (@collection || @model)

 _(options).extend
   complete: =>
     @removeLoading()

 @renderLoading()
 (@collection || @model).fetch options

  return @
View.fetch
Backbone.View::fetch = (options={})->
  return @ unless (@collection || @model)

 _(options).extend
   complete: =>
     @removeLoading()

 @renderLoading()
 (@collection || @model).fetch options

  return @
                             view.fetch()
Lazy fetching
class LazyFetchView extends Backbone.View
  render: ->
    if @model.isFullyFetched()
      # if the data is ready we render it
      $(@el).html ...
    else
      # otherwise we fetch the data
      # rendering the loading indicator
      @fetch()
    return @
Be professional: with
   Jasmine BDD.
Why Jasmine?
BDD
BDD
rspec like!
given a delete button view
when the user clicks the view
then it should delete the model
Jasmine:
              given a delete button view
              when the user clicks the view
              then it should delete the model


describe 'DeleteButtonView', ->

 context 'when the user clicks the view', =>

   it 'should delete the model'
describe 'DeleteButton', ->

 context 'when the user clicks the view', =>

   it 'should delete the model'
describe 'DeleteButton', ->

 context 'when the user clicks the view', =>

   it 'should delete the model', =>
     expect(@model.delete).toHaveBeenCalledOnce()
describe 'DeleteButton', ->

 context 'when the user clicks the view', =>

   it 'should delete the model', =>
     expect(@model.delete).toHaveBeenCalledOnce()



                  http://sinonjs.org/

        https://github.com/froots/jasmine-sinon
describe 'DeleteButton', ->
  beforeEach =>
    @model = new Backbone.Model
    @deleteButton = new DeleteButton(model: @model)

 context 'when the user clicks the view', =>

   it 'should delete the model', =>
     expect(@model.delete).toHaveBeenCalledOnce()
describe 'DeleteButton', ->
  beforeEach =>
    @model = new Backbone.Model
    @deleteButton = new DeleteButton(model: @model)

 context 'when the user clicks the view', =>
   beforeEach =>
     sinon.spy @model, 'delete'

   it 'should delete the model', =>
     expect(@model.delete).toHaveBeenCalledOnce()
describe 'DeleteButton', ->
  beforeEach =>
    @model = new Backbone.Model
    @deleteButton = new DeleteButton(model: @model)

 context 'when the user clicks the view', =>
   beforeEach =>
     sinon.spy @model, 'delete'

     @deleteButton.render()
     $(@deleteButton.el).click()

   it 'should delete the model', =>
     expect(@model.delete).toHaveBeenCalledOnce()
Run it headless!


      Text




       http://johnbintz.github.com/jasmine-headless-webkit/
http://tinnedfruit.com/2011/03/03/testing-backbone-apps-
                  with-jasmine-sinon.html
Further reading

• https://github.com/creationix/haml-js
• https://github.com/fnando/i18n-js
• http://documentcloud.github.com/underscore/
• https://github.com/velesin/jasmine-jquery
So long and thanks for
      all the fish!
         @pirelenito
     github.com/pirelenito
      about.me/pirelenito

More Related Content

PDF
Django Rest Framework and React and Redux, Oh My!
PDF
Keeping the frontend under control with Symfony and Webpack
PDF
Ember.js - A JavaScript framework for creating ambitious web applications
PDF
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
PDF
Introduction to AngularJS For WordPress Developers
PDF
Sane Async Patterns
PDF
The DOM is a Mess @ Yahoo
PPTX
Ember - introduction
Django Rest Framework and React and Redux, Oh My!
Keeping the frontend under control with Symfony and Webpack
Ember.js - A JavaScript framework for creating ambitious web applications
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Introduction to AngularJS For WordPress Developers
Sane Async Patterns
The DOM is a Mess @ Yahoo
Ember - introduction

What's hot (20)

PDF
HTML5: friend or foe (to Flash)?
PPTX
IndexedDB - Querying and Performance
PPTX
Good karma: UX Patterns and Unit Testing in Angular with Karma
PDF
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
PDF
Workshop 27: Isomorphic web apps with ReactJS
PDF
Future of Web Apps: Google Gears
PPTX
Intro to Ember.JS 2016
PDF
Symfony tips and tricks
PDF
Caldera Learn - LoopConf WP API + Angular FTW Workshop
PDF
Play vs Rails
PDF
The JavaFX Ecosystem
PDF
Rails 3: Dashing to the Finish
PPT
Writing Pluggable Software
PPT
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
PDF
Intro to Ember.js
PDF
The Best (and Worst) of Django
PDF
Intro to React
PDF
Workshop 3: JavaScript build tools
PDF
Thomas Fuchs Presentation
PDF
Introducing Assetic: Asset Management for PHP 5.3
HTML5: friend or foe (to Flash)?
IndexedDB - Querying and Performance
Good karma: UX Patterns and Unit Testing in Angular with Karma
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
Workshop 27: Isomorphic web apps with ReactJS
Future of Web Apps: Google Gears
Intro to Ember.JS 2016
Symfony tips and tricks
Caldera Learn - LoopConf WP API + Angular FTW Workshop
Play vs Rails
The JavaFX Ecosystem
Rails 3: Dashing to the Finish
Writing Pluggable Software
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
Intro to Ember.js
The Best (and Worst) of Django
Intro to React
Workshop 3: JavaScript build tools
Thomas Fuchs Presentation
Introducing Assetic: Asset Management for PHP 5.3
Ad

Similar to Single Page Web Applications with CoffeeScript, Backbone and Jasmine (20)

PDF
SproutCore and the Future of Web Apps
PDF
Crossing the Bridge: Connecting Rails and your Front-end Framework
PDF
Ruby on Rails - Introduction
KEY
[Coscup 2012] JavascriptMVC
PDF
HTML5 for the Silverlight Guy
KEY
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
PDF
Doctrine For Beginners
PDF
[Bristol WordPress] Supercharging WordPress Development
PDF
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
PDF
Integrating React.js Into a PHP Application
PDF
Working with Javascript in Rails
PDF
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
PDF
Having Fun with Play
KEY
A tour on ruby and friends
PDF
Real life-coffeescript
KEY
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
PPTX
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
KEY
Ruby/Rails
PDF
Dependency Management with RequireJS
PDF
Backbone.js — Introduction to client-side JavaScript MVC
SproutCore and the Future of Web Apps
Crossing the Bridge: Connecting Rails and your Front-end Framework
Ruby on Rails - Introduction
[Coscup 2012] JavascriptMVC
HTML5 for the Silverlight Guy
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Doctrine For Beginners
[Bristol WordPress] Supercharging WordPress Development
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
Integrating React.js Into a PHP Application
Working with Javascript in Rails
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
Having Fun with Play
A tour on ruby and friends
Real life-coffeescript
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
Ruby/Rails
Dependency Management with RequireJS
Backbone.js — Introduction to client-side JavaScript MVC
Ad

Recently uploaded (20)

PDF
Reimagining Insurance: Connected Data for Confident Decisions.pdf
PDF
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
PDF
CIFDAQ's Teaching Thursday: Moving Averages Made Simple
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PPTX
Comunidade Salesforce São Paulo - Desmistificando o Omnistudio (Vlocity)
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Dell Pro 14 Plus: Be better prepared for what’s coming
PDF
Security features in Dell, HP, and Lenovo PC systems: A research-based compar...
PDF
madgavkar20181017ppt McKinsey Presentation.pdf
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Why Endpoint Security Is Critical in a Remote Work Era?
PDF
Doc9.....................................
PDF
Event Presentation Google Cloud Next Extended 2025
PDF
Revolutionize Operations with Intelligent IoT Monitoring and Control
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PDF
CIFDAQ's Market Wrap: Ethereum Leads, Bitcoin Lags, Institutions Shift
PDF
Chapter 2 Digital Image Fundamentals.pdf
PDF
How Onsite IT Support Drives Business Efficiency, Security, and Growth.pdf
PDF
Enable Enterprise-Ready Security on IBM i Systems.pdf
PDF
A Day in the Life of Location Data - Turning Where into How.pdf
Reimagining Insurance: Connected Data for Confident Decisions.pdf
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
CIFDAQ's Teaching Thursday: Moving Averages Made Simple
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
Comunidade Salesforce São Paulo - Desmistificando o Omnistudio (Vlocity)
Understanding_Digital_Forensics_Presentation.pptx
Dell Pro 14 Plus: Be better prepared for what’s coming
Security features in Dell, HP, and Lenovo PC systems: A research-based compar...
madgavkar20181017ppt McKinsey Presentation.pdf
NewMind AI Weekly Chronicles - August'25 Week I
Why Endpoint Security Is Critical in a Remote Work Era?
Doc9.....................................
Event Presentation Google Cloud Next Extended 2025
Revolutionize Operations with Intelligent IoT Monitoring and Control
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
CIFDAQ's Market Wrap: Ethereum Leads, Bitcoin Lags, Institutions Shift
Chapter 2 Digital Image Fundamentals.pdf
How Onsite IT Support Drives Business Efficiency, Security, and Growth.pdf
Enable Enterprise-Ready Security on IBM i Systems.pdf
A Day in the Life of Location Data - Turning Where into How.pdf

Single Page Web Applications with CoffeeScript, Backbone and Jasmine

Editor's Notes