SlideShare a Scribd company logo
1 of 77
Download to read offline
Unobtrusive Ajax
   With Rails
 Dan Webb (dan@danwebb.net)
Overview
    A bit of history
★

    What is unobtrusive scripting?
★

    The UJS Plugin
★

    Casestudy
★

    Ranting Upcoming UJS Features
★
The dark days of
    DHTML
Then web standards
      arrived
The Client-side Cake

        Style - CSS




     Content - (X)HTML
What web standards
          did for us
    More maintainable
★

    More accessible
★

    Leaner pages
★

    Platform independent (print, mobile...)
★

    'Future-proof' as well as backwards
★
    compatible
JavaScript got a
   bad name
It deserved it
Web 2.0
Folksonomies
Massive text boxes
Social software
and Ajax...
JavaScript is trendy
      again!
Browser support is
   much better
We learnt our
lessons from the
  DHTML days
What did we learn?
Unobtrusive DOM
   Scripting
It's an approach to
browser UI design
It's about separating
   content and style
    from behaviour
Behaviour: A new layer for
   the client-side cake
        Behaviour - JavaScript


             Style - CSS


        Content - (X)HTML
It's enhancing a
working application
so it degrades
 gracefully when
things don't work
It's not just about
putting JavaScript in
    a different file
It's not rocket
     science
It's not the
'Rails Way'
An example:
link_to_remote
<%= link_to_remote 'View description',
                   :controller => 'product',
                   :action => 'desc',
                   :id => @product.id %>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/
desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
# better...

<a href=quot;/product/desc/1quot; onclick=quot;new
Ajax.Request(this.href, {asynchronous:true,
evalScripts:true}); return false;quot;>View
description</a>
It's not possible to
     do that with
   link_to_remote
<% @products.each do |product| %>

<%= link_to_remote 'View description',
                   :controller => 'product',
                   :action => 'desc',
                   :id => @product.id %>

<% end %>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true});
return false;quot;>View description</a>
<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>

<a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>
Getting started
The UJS Plugin
    A plugin to aid unobtrusive scripting
★
    with Rails
    Allows you to define behaviours via
★
    CSS selectors
    Keeps script in an external, cacheable
★
    files
    www.ujs4rails.com - check it out!
★
Remote Links
<ul id=quot;outlinequot;>

  <% @items.each do |item| %>

  <li><%= link_to :action => 'more',
                  :id => @item.id %></li>

  <% end %>

</ul>
<ul id=quot;outlinequot;>

  <% @items.each do |item| %>

  <li><%= link_to :action => 'more',
                  :id => @item.id %></li>

  <% end %>

</ul>

<% apply_behaviour '#outline a:click',
   'new Ajax.Request(this.href); return false;' %>
<ul id=quot;outlinequot;>

  <% @items.each do |item| %>

  <li><%= link_to :action => 'more',
                  :id => @item.id %></li>

  <% end %>

</ul>

<% apply_behaviour '#outline a', make_remote_link %>
What about links
with side-effects?
Links should never
 have side effects
Use a button



<%= button_to 'Remove from basket',
              :method => :delete %>
<form class=quot;button-toquot; action=quot;/basket/2quot; method=quot;postquot;>

  <input type=quot;hiddenquot; name=quot;_methodquot; value=quot;deletequot; />

  <input type=quot;submitquot; value=quot;Remove from basketquot; />

</form>
Then attach the behaviour


<%= button_to 'Remove from basket',
              :method => :delete %>
<% apply_behaviour 'form.button-to',
                   make_remote_form %>
Hijacking forms
<%= form_tag :url => entries_url, :id => 'comment' %>

  <%= text_field :name %>

  <%= text_field :email %>

  <%= text_area :comment %>

  <%= submit_tag 'Post comment' %>

<%= end_form_tag %>
<%= form_tag :url => entries_url, :id => 'comment' %>

  <%= text_field :name %>

  <%= text_field :email %>

  <%= text_area :comment %>

  <%= submit_tag 'Post comment' %>

<%= end_form_tag %>



<% apply_behaviour '#comment:submit',
   'new Ajax.Request(this.action, { parameters :
   Form.serialize(this)}); return false;' %>
<%= form_tag :url => entries_url, :id => 'comment' %>

  <%= text_field :name %>

  <%= text_field :email %>

  <%= text_area :comment %>

  <%= submit_tag 'Post comment' %>

<%= end_form_tag %>



<% apply_behaviour '#comment', make_remote_form %>
A Case Study

Sneakr.com: A Web 2.0, Ajax Trainer Shop
routes.rb


map.resource :products

map.resource :basket, :controller => 'basket',

             :collection => {:clear => :post}
The Product Controller
class ProductController < ApplicationController

  def index # show all products

      @products = Product.find :all

  end

  def show # show the details of a product

      @product = Product.find params[:id]

  end

end
index.rhtml

<div id=quot;cataloguequot;>
  <%= render :partial => 'products' %>
</div>
<div id=quot;basketquot;>
  <%= render :partial => 'basket' %>
</div>
_products.rhtml

<ul>

  <% @products.each do |product| %>

    <li id=quot;<%= product.id %>_prodquot;>
    <%= link_to product.name, product_url(product) %>
    <%= product.description %>
    </li>

  <% end %>

</ul>
show.rhtml


<h1><%= @product.name %></h1>

<p><%= image_tag @product.photo.public_filename %></p>

<p><%= @product.description %></p>

<p><%= button_to 'Add To Basket', basket_url
(@product), :method => :put %></p>
The Basket Controller

class BasketController < ApplicationController

  def update

      @product = Product.find params[:id]
      @basket << @product

      redirect_to products_url

  end

end
We're done!
now to add the Ajax
<% apply_behaviours do


   on '#catalogue li',
       make_draggable(:revert => true)

    on '#basket', make_drop_receiving(
      :url => basket_url,
      :with => quot;'_method=put&id=' +
        encodeURIComponent(element.id)quot;

    )

end %>
<% apply_behaviours do


   on '#catalogue li',
       make_draggable(:revert => true)

    on '#basket', make_drop_receiving(
      :url => basket_url,
      :with => quot;'_method=put&id=' +
        encodeURIComponent(element.id)quot;

    )

end %>
So how do we deal
 with this on the
   server-side?
respond_to
class BasketController < ApplicationController

  def update

      @product = Product.find params[:id]
      @basket << @product

      redirect_to products_url

  end

end
class BasketController < ApplicationController

  def update

      @product = Product.find params[:id]
      @basket << @product

      respond_to do |type|
        type.html { redirect_to products_url }
        type.js
      end

  end

end
update.rjs



page.replace_html 'basket',
                  :partial => 'basket'
Take a look for
           yourself...
http://www.danwebb.net/railsconf2006/ujs_shopping.zip
We have no control
     over the
 environment our
 JavaScript runs in
Code defensively
The path to enlightenment
    Write a working application using
★
    semantic HTML
    Style it with CSS
★

    Write JavaScript that 'hijacks' the page
★
    elements to enhance the UI
    Learn JavaScript and DOM Scripting
★
Further Reading
    The JavaScript articles on A List Apart
★
    (alistapart.com)
    Unobtrusive Scripting by Christian
★
    Heilmann (onlinetools.org)
    Jeremy Keith's presentations, book and
★
    articles (domscripting.com)
    Google it!
★
Upcoming in UJS
    Improved testing (custom assertions)
★

    Improved debugging
★

    More behaviour helpers
★

    More tutorials on ujs4rails.com
★
And finally...



<%= apply_behaviour @products, make_draggable %>
<% div_for @product, :behavior => make_draggable do %>

<h2><%= @product.name %></h2>
<p><%= @product.description %></p>

<% end %>
Questions?

More Related Content

What's hot

High Performance Ajax Applications
High Performance Ajax ApplicationsHigh Performance Ajax Applications
High Performance Ajax Applications
Julien Lecomte
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
Yehuda Katz
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Paulo Ragonha
 
Grails Simple Login
Grails Simple LoginGrails Simple Login
Grails Simple Login
moniguna
 

What's hot (20)

Laravel 8 export data as excel file with example
Laravel 8 export data as excel file with exampleLaravel 8 export data as excel file with example
Laravel 8 export data as excel file with example
 
High Performance Ajax Applications
High Performance Ajax ApplicationsHigh Performance Ajax Applications
High Performance Ajax Applications
 
Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!
 
Redux vs Alt
Redux vs AltRedux vs Alt
Redux vs Alt
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript librariesJazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 
Building a JavaScript Library
Building a JavaScript LibraryBuilding a JavaScript Library
Building a JavaScript Library
 
Grails Simple Login
Grails Simple LoginGrails Simple Login
Grails Simple Login
 
An Introduction to ReactJS
An Introduction to ReactJSAn Introduction to ReactJS
An Introduction to ReactJS
 
Building a js widget
Building a js widgetBuilding a js widget
Building a js widget
 
Choosing a Javascript Framework
Choosing a Javascript FrameworkChoosing a Javascript Framework
Choosing a Javascript Framework
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux Introduction
 
React Facebook JavaScript Library
React Facebook JavaScript LibraryReact Facebook JavaScript Library
React Facebook JavaScript Library
 
WordPress and Ajax
WordPress and AjaxWordPress and Ajax
WordPress and Ajax
 
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
 
SproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFestSproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFest
 
ReactJs presentation
ReactJs presentationReactJs presentation
ReactJs presentation
 
REACT.JS : Rethinking UI Development Using JavaScript
REACT.JS : Rethinking UI Development Using JavaScriptREACT.JS : Rethinking UI Development Using JavaScript
REACT.JS : Rethinking UI Development Using JavaScript
 

Viewers also liked (8)

Secretsofrubyonrails
SecretsofrubyonrailsSecretsofrubyonrails
Secretsofrubyonrails
 
State Of Rails 05
State Of Rails 05State Of Rails 05
State Of Rails 05
 
Fisl6
Fisl6Fisl6
Fisl6
 
Rails Conf Talk Slides
Rails Conf Talk SlidesRails Conf Talk Slides
Rails Conf Talk Slides
 
Ugo Cei Presentation
Ugo Cei PresentationUgo Cei Presentation
Ugo Cei Presentation
 
Extractingrails
ExtractingrailsExtractingrails
Extractingrails
 
Our Opinions!
Our Opinions!Our Opinions!
Our Opinions!
 
Workin On The Rails Road
Workin On The Rails RoadWorkin On The Rails Road
Workin On The Rails Road
 

Similar to Dan Webb Presentation

Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
Chris Alfano
 
jQuery and Rails, Sitting in a Tree
jQuery and Rails, Sitting in a TreejQuery and Rails, Sitting in a Tree
jQuery and Rails, Sitting in a Tree
adamlogic
 
Remote code-with-expression-language-injection
Remote code-with-expression-language-injectionRemote code-with-expression-language-injection
Remote code-with-expression-language-injection
Mickey Jack
 
Spca2014 hillier 3rd party_javascript_libraries
Spca2014 hillier 3rd party_javascript_librariesSpca2014 hillier 3rd party_javascript_libraries
Spca2014 hillier 3rd party_javascript_libraries
NCCOMMS
 
Bulletproof Ajax
Bulletproof AjaxBulletproof Ajax
Bulletproof Ajax
adactio
 
Introduction to angular js july 6th 2014
Introduction to angular js   july 6th 2014Introduction to angular js   july 6th 2014
Introduction to angular js july 6th 2014
Simona Clapan
 

Similar to Dan Webb Presentation (20)

Working with Javascript in Rails
Working with Javascript in RailsWorking with Javascript in Rails
Working with Javascript in Rails
 
Unobtrusive JavaScript
Unobtrusive JavaScriptUnobtrusive JavaScript
Unobtrusive JavaScript
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
 
Course CodeSchool - Shaping up with Angular.js
Course CodeSchool - Shaping up with Angular.jsCourse CodeSchool - Shaping up with Angular.js
Course CodeSchool - Shaping up with Angular.js
 
1 ppt-ajax with-j_query
1 ppt-ajax with-j_query1 ppt-ajax with-j_query
1 ppt-ajax with-j_query
 
jQuery and Rails, Sitting in a Tree
jQuery and Rails, Sitting in a TreejQuery and Rails, Sitting in a Tree
jQuery and Rails, Sitting in a Tree
 
Kakunin E2E framework showcase
Kakunin E2E framework showcaseKakunin E2E framework showcase
Kakunin E2E framework showcase
 
243329387 angular-docs
243329387 angular-docs243329387 angular-docs
243329387 angular-docs
 
Get AngularJS Started!
Get AngularJS Started!Get AngularJS Started!
Get AngularJS Started!
 
Ajax Under The Hood
Ajax Under The HoodAjax Under The Hood
Ajax Under The Hood
 
Remote code-with-expression-language-injection
Remote code-with-expression-language-injectionRemote code-with-expression-language-injection
Remote code-with-expression-language-injection
 
Spca2014 hillier 3rd party_javascript_libraries
Spca2014 hillier 3rd party_javascript_librariesSpca2014 hillier 3rd party_javascript_libraries
Spca2014 hillier 3rd party_javascript_libraries
 
The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
Bulletproof Ajax
Bulletproof AjaxBulletproof Ajax
Bulletproof Ajax
 
Bulletproof Ajax
Bulletproof AjaxBulletproof Ajax
Bulletproof Ajax
 
Ajax on drupal the right way - DrupalCamp Campinas, São Paulo, Brazil 2016
Ajax on drupal the right way - DrupalCamp Campinas, São Paulo, Brazil 2016Ajax on drupal the right way - DrupalCamp Campinas, São Paulo, Brazil 2016
Ajax on drupal the right way - DrupalCamp Campinas, São Paulo, Brazil 2016
 
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
The Return of JavaScript: 3 Open-Source Projects that are driving JavaScript'...
 
Unit 2.4
Unit 2.4Unit 2.4
Unit 2.4
 
Introduction to angular js july 6th 2014
Introduction to angular js   july 6th 2014Introduction to angular js   july 6th 2014
Introduction to angular js july 6th 2014
 

More from RubyOnRails_dude

More from RubyOnRails_dude (7)

Slides
SlidesSlides
Slides
 
Marcel Molina Jr. Presentation
Marcel Molina Jr. PresentationMarcel Molina Jr. Presentation
Marcel Molina Jr. Presentation
 
Rails4 Days
Rails4 DaysRails4 Days
Rails4 Days
 
Till Vollmer Presentation
Till Vollmer PresentationTill Vollmer Presentation
Till Vollmer Presentation
 
Programminghappiness
ProgramminghappinessProgramminghappiness
Programminghappiness
 
Pursuitofbeauty
PursuitofbeautyPursuitofbeauty
Pursuitofbeauty
 
Worldofresources
WorldofresourcesWorldofresources
Worldofresources
 

Recently uploaded

Recently uploaded (20)

Puri CALL GIRL ❤️8084732287❤️ CALL GIRLS IN ESCORT SERVICE WE ARW PROVIDING
Puri CALL GIRL ❤️8084732287❤️ CALL GIRLS IN ESCORT SERVICE WE ARW PROVIDINGPuri CALL GIRL ❤️8084732287❤️ CALL GIRLS IN ESCORT SERVICE WE ARW PROVIDING
Puri CALL GIRL ❤️8084732287❤️ CALL GIRLS IN ESCORT SERVICE WE ARW PROVIDING
 
Buy gmail accounts.pdf buy Old Gmail Accounts
Buy gmail accounts.pdf buy Old Gmail AccountsBuy gmail accounts.pdf buy Old Gmail Accounts
Buy gmail accounts.pdf buy Old Gmail Accounts
 
Horngren’s Cost Accounting A Managerial Emphasis, Canadian 9th edition soluti...
Horngren’s Cost Accounting A Managerial Emphasis, Canadian 9th edition soluti...Horngren’s Cost Accounting A Managerial Emphasis, Canadian 9th edition soluti...
Horngren’s Cost Accounting A Managerial Emphasis, Canadian 9th edition soluti...
 
Phases of Negotiation .pptx
 Phases of Negotiation .pptx Phases of Negotiation .pptx
Phases of Negotiation .pptx
 
Chennai Call Gril 80022//12248 Only For Sex And High Profile Best Gril Sex Av...
Chennai Call Gril 80022//12248 Only For Sex And High Profile Best Gril Sex Av...Chennai Call Gril 80022//12248 Only For Sex And High Profile Best Gril Sex Av...
Chennai Call Gril 80022//12248 Only For Sex And High Profile Best Gril Sex Av...
 
Berhampur 70918*19311 CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
Berhampur 70918*19311 CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDINGBerhampur 70918*19311 CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
Berhampur 70918*19311 CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
 
GUWAHATI 💋 Call Girl 9827461493 Call Girls in Escort service book now
GUWAHATI 💋 Call Girl 9827461493 Call Girls in  Escort service book nowGUWAHATI 💋 Call Girl 9827461493 Call Girls in  Escort service book now
GUWAHATI 💋 Call Girl 9827461493 Call Girls in Escort service book now
 
Escorts in Nungambakkam Phone 8250092165 Enjoy 24/7 Escort Service Enjoy Your...
Escorts in Nungambakkam Phone 8250092165 Enjoy 24/7 Escort Service Enjoy Your...Escorts in Nungambakkam Phone 8250092165 Enjoy 24/7 Escort Service Enjoy Your...
Escorts in Nungambakkam Phone 8250092165 Enjoy 24/7 Escort Service Enjoy Your...
 
Lundin Gold - Q1 2024 Conference Call Presentation (Revised)
Lundin Gold - Q1 2024 Conference Call Presentation (Revised)Lundin Gold - Q1 2024 Conference Call Presentation (Revised)
Lundin Gold - Q1 2024 Conference Call Presentation (Revised)
 
PARK STREET 💋 Call Girl 9827461493 Call Girls in Escort service book now
PARK STREET 💋 Call Girl 9827461493 Call Girls in  Escort service book nowPARK STREET 💋 Call Girl 9827461493 Call Girls in  Escort service book now
PARK STREET 💋 Call Girl 9827461493 Call Girls in Escort service book now
 
Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1
 
Putting the SPARK into Virtual Training.pptx
Putting the SPARK into Virtual Training.pptxPutting the SPARK into Virtual Training.pptx
Putting the SPARK into Virtual Training.pptx
 
Cannabis Legalization World Map: 2024 Updated
Cannabis Legalization World Map: 2024 UpdatedCannabis Legalization World Map: 2024 Updated
Cannabis Legalization World Map: 2024 Updated
 
Marel Q1 2024 Investor Presentation from May 8, 2024
Marel Q1 2024 Investor Presentation from May 8, 2024Marel Q1 2024 Investor Presentation from May 8, 2024
Marel Q1 2024 Investor Presentation from May 8, 2024
 
Arti Languages Pre Seed Teaser Deck 2024.pdf
Arti Languages Pre Seed Teaser Deck 2024.pdfArti Languages Pre Seed Teaser Deck 2024.pdf
Arti Languages Pre Seed Teaser Deck 2024.pdf
 
Falcon Invoice Discounting: Empowering Your Business Growth
Falcon Invoice Discounting: Empowering Your Business GrowthFalcon Invoice Discounting: Empowering Your Business Growth
Falcon Invoice Discounting: Empowering Your Business Growth
 
Berhampur 70918*19311 CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
Berhampur 70918*19311 CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDINGBerhampur 70918*19311 CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
Berhampur 70918*19311 CALL GIRLS IN ESCORT SERVICE WE ARE PROVIDING
 
Lucknow Housewife Escorts by Sexy Bhabhi Service 8250092165
Lucknow Housewife Escorts  by Sexy Bhabhi Service 8250092165Lucknow Housewife Escorts  by Sexy Bhabhi Service 8250092165
Lucknow Housewife Escorts by Sexy Bhabhi Service 8250092165
 
HomeRoots Pitch Deck | Investor Insights | April 2024
HomeRoots Pitch Deck | Investor Insights | April 2024HomeRoots Pitch Deck | Investor Insights | April 2024
HomeRoots Pitch Deck | Investor Insights | April 2024
 
Getting Real with AI - Columbus DAW - May 2024 - Nick Woo from AlignAI
Getting Real with AI - Columbus DAW - May 2024 - Nick Woo from AlignAIGetting Real with AI - Columbus DAW - May 2024 - Nick Woo from AlignAI
Getting Real with AI - Columbus DAW - May 2024 - Nick Woo from AlignAI
 

Dan Webb Presentation

  • 1. Unobtrusive Ajax With Rails Dan Webb (dan@danwebb.net)
  • 2. Overview A bit of history ★ What is unobtrusive scripting? ★ The UJS Plugin ★ Casestudy ★ Ranting Upcoming UJS Features ★
  • 3. The dark days of DHTML
  • 4.
  • 5.
  • 6.
  • 8. The Client-side Cake Style - CSS Content - (X)HTML
  • 9. What web standards did for us More maintainable ★ More accessible ★ Leaner pages ★ Platform independent (print, mobile...) ★ 'Future-proof' as well as backwards ★ compatible
  • 10. JavaScript got a bad name
  • 18. Browser support is much better
  • 19. We learnt our lessons from the DHTML days
  • 20. What did we learn?
  • 21. Unobtrusive DOM Scripting
  • 22. It's an approach to browser UI design
  • 23. It's about separating content and style from behaviour
  • 24. Behaviour: A new layer for the client-side cake Behaviour - JavaScript Style - CSS Content - (X)HTML
  • 26. so it degrades gracefully when things don't work
  • 27. It's not just about putting JavaScript in a different file
  • 28. It's not rocket science
  • 31. <%= link_to_remote 'View description', :controller => 'product', :action => 'desc', :id => @product.id %>
  • 32. <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/ desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>
  • 33. # better... <a href=quot;/product/desc/1quot; onclick=quot;new Ajax.Request(this.href, {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>
  • 34. It's not possible to do that with link_to_remote
  • 35. <% @products.each do |product| %> <%= link_to_remote 'View description', :controller => 'product', :action => 'desc', :id => @product.id %> <% end %>
  • 36. <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>
  • 37. <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a> <a href=quot;#quot; onclick=quot;new Ajax.Request('/product/desc/1', {asynchronous:true, evalScripts:true}); return false;quot;>View description</a>
  • 39. The UJS Plugin A plugin to aid unobtrusive scripting ★ with Rails Allows you to define behaviours via ★ CSS selectors Keeps script in an external, cacheable ★ files www.ujs4rails.com - check it out! ★
  • 41. <ul id=quot;outlinequot;> <% @items.each do |item| %> <li><%= link_to :action => 'more', :id => @item.id %></li> <% end %> </ul>
  • 42. <ul id=quot;outlinequot;> <% @items.each do |item| %> <li><%= link_to :action => 'more', :id => @item.id %></li> <% end %> </ul> <% apply_behaviour '#outline a:click', 'new Ajax.Request(this.href); return false;' %>
  • 43. <ul id=quot;outlinequot;> <% @items.each do |item| %> <li><%= link_to :action => 'more', :id => @item.id %></li> <% end %> </ul> <% apply_behaviour '#outline a', make_remote_link %>
  • 44. What about links with side-effects?
  • 45. Links should never have side effects
  • 46. Use a button <%= button_to 'Remove from basket', :method => :delete %>
  • 47. <form class=quot;button-toquot; action=quot;/basket/2quot; method=quot;postquot;> <input type=quot;hiddenquot; name=quot;_methodquot; value=quot;deletequot; /> <input type=quot;submitquot; value=quot;Remove from basketquot; /> </form>
  • 48. Then attach the behaviour <%= button_to 'Remove from basket', :method => :delete %> <% apply_behaviour 'form.button-to', make_remote_form %>
  • 50. <%= form_tag :url => entries_url, :id => 'comment' %> <%= text_field :name %> <%= text_field :email %> <%= text_area :comment %> <%= submit_tag 'Post comment' %> <%= end_form_tag %>
  • 51. <%= form_tag :url => entries_url, :id => 'comment' %> <%= text_field :name %> <%= text_field :email %> <%= text_area :comment %> <%= submit_tag 'Post comment' %> <%= end_form_tag %> <% apply_behaviour '#comment:submit', 'new Ajax.Request(this.action, { parameters : Form.serialize(this)}); return false;' %>
  • 52. <%= form_tag :url => entries_url, :id => 'comment' %> <%= text_field :name %> <%= text_field :email %> <%= text_area :comment %> <%= submit_tag 'Post comment' %> <%= end_form_tag %> <% apply_behaviour '#comment', make_remote_form %>
  • 53. A Case Study Sneakr.com: A Web 2.0, Ajax Trainer Shop
  • 54. routes.rb map.resource :products map.resource :basket, :controller => 'basket', :collection => {:clear => :post}
  • 55. The Product Controller class ProductController < ApplicationController def index # show all products @products = Product.find :all end def show # show the details of a product @product = Product.find params[:id] end end
  • 56. index.rhtml <div id=quot;cataloguequot;> <%= render :partial => 'products' %> </div> <div id=quot;basketquot;> <%= render :partial => 'basket' %> </div>
  • 57. _products.rhtml <ul> <% @products.each do |product| %> <li id=quot;<%= product.id %>_prodquot;> <%= link_to product.name, product_url(product) %> <%= product.description %> </li> <% end %> </ul>
  • 58. show.rhtml <h1><%= @product.name %></h1> <p><%= image_tag @product.photo.public_filename %></p> <p><%= @product.description %></p> <p><%= button_to 'Add To Basket', basket_url (@product), :method => :put %></p>
  • 59. The Basket Controller class BasketController < ApplicationController def update @product = Product.find params[:id] @basket << @product redirect_to products_url end end
  • 61. now to add the Ajax
  • 62. <% apply_behaviours do on '#catalogue li', make_draggable(:revert => true) on '#basket', make_drop_receiving( :url => basket_url, :with => quot;'_method=put&id=' + encodeURIComponent(element.id)quot; ) end %>
  • 63. <% apply_behaviours do on '#catalogue li', make_draggable(:revert => true) on '#basket', make_drop_receiving( :url => basket_url, :with => quot;'_method=put&id=' + encodeURIComponent(element.id)quot; ) end %>
  • 64. So how do we deal with this on the server-side?
  • 66. class BasketController < ApplicationController def update @product = Product.find params[:id] @basket << @product redirect_to products_url end end
  • 67. class BasketController < ApplicationController def update @product = Product.find params[:id] @basket << @product respond_to do |type| type.html { redirect_to products_url } type.js end end end
  • 69. Take a look for yourself... http://www.danwebb.net/railsconf2006/ujs_shopping.zip
  • 70. We have no control over the environment our JavaScript runs in
  • 72. The path to enlightenment Write a working application using ★ semantic HTML Style it with CSS ★ Write JavaScript that 'hijacks' the page ★ elements to enhance the UI Learn JavaScript and DOM Scripting ★
  • 73. Further Reading The JavaScript articles on A List Apart ★ (alistapart.com) Unobtrusive Scripting by Christian ★ Heilmann (onlinetools.org) Jeremy Keith's presentations, book and ★ articles (domscripting.com) Google it! ★
  • 74. Upcoming in UJS Improved testing (custom assertions) ★ Improved debugging ★ More behaviour helpers ★ More tutorials on ujs4rails.com ★
  • 75. And finally... <%= apply_behaviour @products, make_draggable %>
  • 76. <% div_for @product, :behavior => make_draggable do %> <h2><%= @product.name %></h2> <p><%= @product.description %></p> <% end %>