Using Unobtrusive JavaScript to Update an Element
As you know, when you upgrade from Rails 2 to 3 you replace this:
link_to_remote "more", :url => {...}
with this:
link_to "more", {...}, :remote => true
But how do you handle the :update option in link_to_remote? In Railscast #205 Ryan Bates demonstrates link_to
with :remote
and a server response that includes JavaScript code to update a particular element in a page, but this practice seems wrong to me. I want my server's response to be a simple HTML fragment which is easy to test and which can be used by different pages (clients) in different ways. I don't think the server should have to know the ID of the target element on the requesting page as it ties the action to the page (a mini-client) and therefore makes it less ge开发者_运维技巧neral (it also feels uglier than a pure HTML response).
So, to be explicit, is there a way to do something like this:
link_to_remote "more", :url => {...}, :update => "products-list"
with Rails 3 and UJS? Or do I have to write JavaScript to capture the server's HTML response and insert it into the right element on the page?
If the latter, please describe the best approach (can link_to
's :remote
option be used at all?).
I'm not 100% sure that this is the Rails-endorsed way to do it, but I've found a solution that works and seems pretty clean. Let's say we have a page that lists the ten most popular products in our database. At the end is a link to load all remaining products via AJAX:
<ul id="products-list">
<li>...</li>
<li>...</li>
<li>...</li>
...
</ul>
<%= link_to "more...", "/products/all", :id => "load-more", :remote => true %>
The server returns plain HTML (so that the link can be used on many different pages and is not bound to particular DOM IDs). We use the ajax:x
events triggered by the Rails UJS drivers (here I'm using jQuery) to grab the server's response and insert it into the right element on the page:
<%= javascript_tag do %>
$("#load-more").bind("ajax:complete", function(et, e){
$("#products-list").html(e.responseText);
});
<% end %>
If desired, we can also use the ajax:loading
event to show a "spinner":
<%= javascript_tag do %>
$("load-more").bind("ajax:loading", function(et, e){
$(this).hide();
$("#products-spinner").show();
});
<% end %>
The Rails UJS drivers trigger four other events as well: ajax:success
, ajax:failure
, ajax:before
, and ajax:after
. See the driver included in your app (public/javascripts/rails.js) for more information.
in the js view /apps/views/product/index.js.erb
you can write JS code such as the following
prototype:
$("products-list").update("<%= escape_javascript(render(@products))%>");
jquery:
$("products-list").html("<%= escape_javascript(render(@products))%>");
or
$("products-list").append("<%= escape_javascript(render(@products))%>");
and it will be executed when the request is successful
yes, you can apply the latter approach (write custom JS to get server response) by using link_to :remote.
you can also choose to get a json response, then update data on the page using JS. in any case, remember to render only the partial, not the entire page.
EDIT:
a sample code, this should make AJAX call when clicking something with id "more", then update a #product-list element in the page:
$("#more").click(function() {
// make a POST call and replace the content
$.post(, function(data) {
$("#products-list").html(data);
});
});
you don't need more code, and you can write some helper to generate this JS, instead of writing code in the view. btw this is yet UJS
精彩评论