1. Javascript, AJAX and scriptaculous on Rails

    or 'All that Web 2.0 stuff '

    Rob Lee

    monkeyhelper labs

    Slides available at: http://www.monkeyhelper.com

  2. Before we begin

    • Show FP site
  3. Javascript and Rails

    • Prototype AJAX, DOM manipulation and manages browser quirks
    • Prototype - 2 sets of helpers AJAX and DOM
    • Scriptaculous builds on top of prototype - visual effects, draggable and sortable elements
  4. First things first

    <%= javascript_include_tag :defaults %>
    or
    <%= javascript_include_tag :prototype %>
    
    <script src="/javascripts/prototype.js" type="text/javascript"></script>
    <script src="/javascripts/effects.js" type="text/javascript"></script>
    <script src="/javascripts/dragdrop.js" type="text/javascript"></script>
    <script src="/javascripts/controls.js" type="text/javascript"></script>
    <script src="/javascripts/application.js" type="text/javascript"></script>  
    
    
  5. Add script helpers to layout/views or nothing works
  6. Prototype and Rails

    Live search

    • Hands up for who knows what AJAX is
    • AJAX - Asynchronous Javascript and XML
    • Live search example
    • DEMO feedplanet
  7. Prototype - Live search example

      <%= text_field_tag  :searchQuery %>
      <%= observe_field(  :searchQuery,
              :frequency  =>  0.5,
              :update     =>  :searchResults,
              :url        =>  { :action =>  :search },
              :loading    =>  "Element.show('search-indicator')",
              :complete   =>  "Element.hide('search-indicator')") %>
      <%= image_tag("indicator.gif",
                    :id     =>  'search-indicator',
                    :style  =>  'display:none;') %>
    
    • This is a view or a partial in a view
  8. Prototype - Live search example

      <%= text_field_tag  :searchQuery %>
      <%= observe_field(  :searchQuery,
              :frequency  =>  0.5,
              :update     =>  :searchResults,
              :url        =>  { :action =>  :search },
              :loading    =>  "Element.show('search-indicator')",
              :complete   =>  "Element.hide('search-indicator')") %>
      <%= image_tag("indicator.gif",
                    :id     =>  'search-indicator',
                    :style  =>  'display:none;') %>
    
  9. Prototype - Live search example

      <%= text_field_tag  :searchQuery %>
      <%= observe_field(  :searchQuery,
              :frequency  =>  0.5,
              :update     =>  :searchResults,
              :url        =>  { :action =>  :search },
              :loading    =>  "Element.show('search-indicator')",
              :complete   =>  "Element.hide('search-indicator')") %>
      <%= image_tag("indicator.gif",
                    :id     =>  'search-indicator',
                    :style  =>  'display:none;') %>
    
  10. Prototype - Live search example

      <%= text_field_tag  :searchQuery %>
      <%= observe_field(  :searchQuery,
              :frequency  =>  0.5,
              :update     =>  :searchResults,
              :url        =>  { :action =>  :search },
              :loading    =>  "Element.show('search-indicator')",
              :complete   =>  "Element.hide('search-indicator')") %>
      <%= image_tag("indicator.gif",
                    :id     =>  'search-indicator',
                    :style  =>  'display:none;') %>
    
  11. Prototype - Live search example

      <%= text_field_tag  :searchQuery %>
      <%= observe_field(  :searchQuery,
              :frequency  =>  0.5,
              :update     =>  :searchResults,
              :url        =>  { :action =>  :search },
              :loading    =>  "Element.show('search-indicator')",
              :complete   =>  "Element.hide('search-indicator')") %>
      <%= image_tag("indicator.gif",
                    :id     =>  'search-indicator',
                    :style  =>  'display:none;') %>
    
  12. Prototype - Live search example

      <%= text_field_tag  :searchQuery %>
      <%= observe_field(  :searchQuery,
              :frequency  =>  0.5,
              :update     =>  :searchResults,
              :url        =>  { :action =>  :search },
              :loading    =>  "Element.show('search-indicator')",
              :complete   =>  "Element.hide('search-indicator')") %>
      <%= image_tag("indicator.gif",
                    :id     =>  'search-indicator',
                    :style  =>  'display:none;') %>
    
    • Mention domain limitation
  13. Prototype - Live search example

     def search
        @raw_phrase = request.raw_post
        @posts = []
        @posts_pages = []
        unless @raw_phrase == ""
          @phrase = "%" + @raw_phrase + "%"
          @post_pages,@posts  = paginate(:entries,
                                         :per_page   =>  12,
                                         :order      =>  "time DESC",
          			             :conditions =>  ["content like ?", @phrase])
        end
        respond_to do |wants|
          wants.html { render :partial => "search"}
          wants.js    { render :partial => "search"}
          wants.xml  { render :xml => @posts.to_xml }
        end
      end
    
    • Mention respond_to and ajax Accepts HTTP header
    • DEMO XML example
  14. Prototype - Live search example

      <%= text_field_tag  :searchQuery %>
      <%= observe_field(  :searchQuery,
              :frequency  =>  0.5,
              :update     =>  :searchResults,
              :url        =>  { :action =>  :search },
              :loading    =>  "Element.show('search-indicator')",
              :complete   =>  "Element.hide('search-indicator')") %>
      <%= image_tag("indicator.gif",
                    :id     =>  'search-indicator',
                    :style  =>  'display:none;') %>
    
    • statuses : loading,loaded,interactive,success,failure,complete
  15. Prototype - Live search example

      <%= text_field_tag  :searchQuery %>
      <%= observe_field(  :searchQuery,
              :frequency  =>  0.5,
              :update     =>  :searchResults,
              :url        =>  { :action =>  :search },
              :loading    =>  "Element.show('search-indicator')",
              :complete   =>  "Element.hide('search-indicator')") %>
      <%= image_tag("indicator.gif",
                    :id     =>  'search-indicator',
                    :style  =>  'display:none;') %>
    
  16. Generic Ajax Process

  17. Scriptaculous

    • Written by Thomas Fuchs - one of the Rails Core Team
  18. Visual effects with Scriptaculous

       <%= link_to_function "[Show|Hide]", 
            visual_effect(:toggle_blind, :links, :duration => 1) %>
    
    <a href="#" onclick="Effect.toggle("links",'blind',
        {duration:1});; return false;">[Show|Hide]</a>
    
    • Mention AGGREGATOR again
    • Many effects are available blindup/down, slideup/down, appear/fade
    • Pulsate, squish, grow
  19. The Scriptaculous event queue

       <%=  link_to_remote "More pictures ...", :update => "images",
        :url => { :action => "index", :blocktype => 'images', :limit=>'30' }, 
        :loading => visual_effect(:slide_up, :imagescontainer ),
        :success => visual_effect(:slide_down, :imagescontainer) %>
    
    • Events on the same DOM element don't play well together
  20. The Scriptaculous event queue

       <%=  link_to_remote "More pictures ...", :update => "images",
        :url => { :action => "index", :blocktype => 'images', :limit=>'30' }, 
        :loading => visual_effect(:slide_up, :imagescontainer, :queue => 'front'),
        :success => visual_effect(:slide_down, :imagescontainer, :queue => 'end') %>
    
    • Scriptaculous effect options

      • Transition -> make a fade effect wobble
    • Standard Javascript Helpers and Macros

      MacroAction
      javascript_tagCreates script tag wrapper
      link_to_functionCreates an anchor tag with an onclick method
      escape_javascriptEscapes quotes in JS strings
    • In-Place Edit Example

      <%= in_place_editor_field :item, :description, {}, {:rows=>10, :cols=>50} %>
      
      • DEMO flickr
    • Javascript Generator class

      • Instantiate a JSGenerator class -> page object, call JSGen methods on
      • Generates blocks of JavaScript code that allow you to change the content and presentation of DOM elements
      • JS Generators also expose scriptaculous methods
    • RJS Templates

      • Require an action in a controller like any other partial
    • Javascript generators and RJS : An example

      page.insert_html :bottom, 'purchasedlist', @item.name
      page.visual_effect :highlight, 'purchasedlist'
      page.replace_html 'totalprice', :partial => 'totalprice'
      
      • The page object allows you to call methods on a representation of the page
      • Generates js which is eval'd on return of AJAX call
    • Javascript generators: An example

      page.insert_html :bottom, 'purchasedlist', @item.name
      page.visual_effect :highlight, 'purchasedlist'
      page.replace_html 'totalprice', :partial => 'totalprice'
      
      • Javascript generators: An example

        page.insert_html :bottom, 'purchasedlist', @item.name
        page.visual_effect :highlight, 'purchasedlist'
        page.replace_html 'totalprice', :partial => 'totalprice'
        
        • Javascript generators: An example

          page.insert_html :bottom, 'purchasedlist', @item.name
          page.visual_effect :highlight, 'purchasedlist'
          page.replace_html 'totalprice', :partial => 'totalprice'
          
          • More fun - iterating over collections

          • JS Generators in the controller