Hey everyone, I'm working on an application and I'm having difficulty with the new Rails 3 link_to. Here's the situation - I have two divs on my "home" page, and each div is populated at document.load with ajax. This works as expected.
In the content of the pages I'm loading into these divs, I want to use the link_to... :remote => true functionality. The source renders as expected with the data-remote="true" tag, but when I click on the links, they're completely ignored (the link is treated as a regular hyperlink).
I've written .rjs files that handle everything properly (because they work when hard-coded), so that's not the issue.
Here's the html source for the ajax-loaded content:
<div>
<a href="/cart/add/2" data-remote="true">Link A</a>
<a href="/cart/add/1" data-remote="true">Link B</a>
</div>
Clicking on one of those links when normally embedded into the page causes my shopping cart to update correctly... however, when I dynamically load this content into the page with AJAX, the link just follows and ignores the data-remote="true"...
Originally I thought it had something to do with prototype not loading correctly in the AJAX stuff, but I've checked all of that and it doesn't change a thing...
I'm really confused... Does anybody have a thought on this?
# add method of controller
def add
product = Product.find_by_id(params[:product_id])
params[:quantity] ||= 1
params[:price] ||= product.price
unless product.nil?
@line = session[:cart].purchase_lines.select {|l| l.product_id == product.id}.first
unless @line.nil?
@line.quantity = (@line.quantity + params[:quantity].to_i)
else # create a new purchase_line in the cart
@line = session[:cart].purchase_lines.build({ :product_id => product.id, :price => params[:price], :quantity => params[:quantity].to_i })
end
else
flash[:error] = "Unable to add the selected product"
end
end
and my rjs
# add.rjs
page.if page['product_' << @line.product_id.to_s] do
page.replace 'product_' << @line.product_id.to_s, :partial => 'line'
page.else
page.insert_html :bottom, 'cart', :partial => 'line'
end
page.replace_html 'sub_total', number_to_currency(session[:cart].sub_total, :unit => '$')
page.replace_html 'tax', number_to_currency(session[:cart].tax, :unit => '$')
page.replace_html 'total', number_to_currency(session[:cart].sub_total+session[:cart].tax, :unit => '$')
page.visual_effect :highlight, 'product_' << @line.product_id.to_s, :duration => 1
I'm pretty sure the problem here is that when your page loads the first time, the Rails UJS javascript library you're using (Prototype by default, or jQuery, etc.) binds a listener to the onclick event of the anchor (link) element. However, when you update your page with new markup dynamically (via ajax in this case) the new anchor tags do not receive this binding because the UJS library only does it's thing when the page first loads. If you're using jQuery as your UJS you should look into the jQuery.live() event handler attachment located in the jQuery API docs
The description from the API is as follows:
Description: Attach a handler to the event for all elements which match the current selector, now and in the future.
Specifically you should give the div that will receive the AJAX loaded content an id let's say "cart-links", then add some javascript to the page similar to the following:
$('#cart-links a').live('click', function() {
// make your AJAX calls here
});
I'm not sure if there's a Prototype equivalent if that's what you're using.
The further I've gotten into javascript and Rails, the more I realize that a lot of the Rails javascript helpers actually make javascript development and AJAX handling more difficult, and I tend to just use raw jQuery.
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With