The main malfunction is that jQuery needs to be told to wait until the DOM has finished rendering before it can start doing anything asynchronously. If you attempt to fire off an asynchronous event (like an .ajax(), .get(), or .load() call) before the browser is ready, the bind for the callback will be missed and nothing will happen when the other end of the call answers.
Given the way RJS worked and without any extra guidance, you'd expect a setup like this to work with a
in your application layout and an <%= button_do 'Add to Cart', line_items_path( :product_id => :product, :remote => true ) %> in the index view.
app/controllers/line_items_controller.rb
And then in app/views/line_items/create.js.erb you would expect something like this to work:
But, it doesn't. It just fails quietly leaving you to google for answers. Even more confusing is the fact that non ajaxy stuff you put in the file see what's happening will work, but nothing after the async function call will.
The solution I found was to wrap the ajax stuff in a document ready function (again in app/views/line_items/create.js.erb):
This forces jQuery to slow it's roll and wait for the DOM to finish its ponderous task before firing off the event. At least, that's what I think is going on... javascript isn't my strong point. But that explanation sounds better than "When I wave the dead chicken like this, the sky makes thunder."
I also found someone that had come up with a solution of binding click events for any button with a "add_to_cart" class to the ajax:success event and use that to update the cart div, but that seemed like a giant trap to maintain and was a nonobvious solution to the problem.
app/controllers/line_items_controller.rb
def create @cart = current_cart product = Product.find( params[:product_id] ) @line_item = @cart.add_product( product.id ) respond_to do |format| if @line_item.save format.html {redirect_to @line_item.cart } format.js else #[.... rest of function ....]
And then in app/views/line_items/create.js.erb you would expect something like this to work:
alert( "This alert will popup" );
$('#cart').load( "<%= escape_javascript( cart_path( @cart ) ) %>" );
alert( "But you will never, ever see this one." );
But, it doesn't. It just fails quietly leaving you to google for answers. Even more confusing is the fact that non ajaxy stuff you put in the file see what's happening will work, but nothing after the async function call will.
The solution I found was to wrap the ajax stuff in a document ready function (again in app/views/line_items/create.js.erb):
alert( "You will see this alert popup.");
$(document).ready( function($) { $('#cart').load( "<%= escape_javascript( cart_path( @cart ) )%>" ); } );
alert( "And you'll see this one, too, after the cart div updates!!!" );
This forces jQuery to slow it's roll and wait for the DOM to finish its ponderous task before firing off the event. At least, that's what I think is going on... javascript isn't my strong point. But that explanation sounds better than "When I wave the dead chicken like this, the sky makes thunder."
I also found someone that had come up with a solution of binding click events for any button with a "add_to_cart" class to the ajax:success event and use that to update the cart div, but that seemed like a giant trap to maintain and was a nonobvious solution to the problem.
No comments:
Post a Comment