Forum: Ruby on Rails RJS Templates and the Replace semantics

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Tom F. (Guest)
on 2005-12-15 21:34
(Received via mailing list)
I have an issue with the way replace_html works in an RJS template.
This is a copy of a post on my blog (http://blog.craz8.com
<http://blog.craz8.com/> ) that describes the problem and my working
solution to the problem.

If I have a collection of things that are output like this:

<div id="things">
<% @things.each do |thing| %>
  <%= render :partial => 'thing' %>
<% end %>
</div>

Or

<div id="things">
<%= render :partial => 'thing', :collection => @things %>
</div>


I can use AJAX to insert a new 'thing' by implementing an RJS template
that does this, reusing the same partial layout:

  page.insert_html :bottom, :partial => 'thing'

but I can't then replace the inserted thing by doing this, as this is
implemented as element.innerHTML:

  page.replace_html "thing-id", :partial => 'thing'

There are ways around this, but they involve moving the outer element of
the thing out of the partial code, splitting the HTML across two files,
or removing and re-adding the element:

  page.remove "thing-id"
  page.insert_html :bottom, :partial => 'thing'

I don't like either of these ideas, so I came up with an improvement
that replaces the entire element in the DOM, similar to IE's
element.outerHTML:

  page.replace_html_element "thing-id", :partial => 'thing'


So, I've written an implementation of replace_html_element that comes in
two parts:

*	The addition to the JavaScriptGenerator class to add a
replace_html_element method
*	An update to the Prototype Element implementation to perform the
client side update.

Add this code to the Application.rb (or in a separate file required by
Application.rb):



# Update the JavaScriptGenerator to add our own functionality
module ActionView
  module Helpers
    module PrototypeHelper
      class JavaScriptGenerator
        def replace_html_element(id, *options_for_render)
          html = render(*options_for_render)
          record "Element.replace(#{id.inspect}, #{html.inspect})"
        end
      end
    end
  end
end


Add this code to your application javascript file:



// Extend the object for our RJS extension to work
Object.extend(Element, {
  replace: function(element, html) {
      var el = $(element);
      if (el.outerHTML) { // IE
        el.outerHTML = html.stripScripts();
    } else {  // Mozilla
          var range = el.ownerDocument.createRange();
        range.selectNodeContents(el);

el.parentNode.replaceChild(range.createContextualFragment(html.stripScri
pts()), el);
    }
    setTimeout(function() {html.evalScripts()}, 10);
  }
 }
);
This topic is locked and can not be replied to.