Written August 29, 2007. Tagged JavaScript, Ruby, Ruby on Rails, Ajax.
RJS (generator methods docs) is pretty cool.
In one RJS template, I wanted to (visually) remove an element with an animation, and then regenerate the entire list of elements when the animation completed. (I regenerate it because it is a top list, that should always have a certain number of elements if possible.)
Now, one can't do
page.visual_effect :puff, @element_id
page.replace 'the_id', :partial => 'list'
since visual effects are asynchronous – the next line of code is executed straight away, not when the effect completes.
Effects have callbacks, such as afterFinish
, but in RJS, you specify the callbacks as strings, not blocks of code. And you can't do
page.visual_effect :puff, @element_id, :afterFinish => "function() { " + page.replace('the_id', :partial => 'list') + " }"
because even though page.replace
will return the generated JS as a string, it also appends that string to the returned JS, so one will end up with something like
Element.replace(…);
new Effect.Puff("the_element_id", {afterFinish:'function() { Element.replace(…); }'});
This is one situation where RJS can seem pretty limited, but this is actually very easily solved.
One can use page#<<
to inject raw JS into the page, just as the other generator methods generate JS and inject into the page. So one can simply wrap the generated JS in a function definition using page#<<
, and then register that function for the callback:
page << "function updateList() {"
page.replace 'the_id', :partial => 'list'
page << "}"
page.visual_effect :puff, @element_id, :afterFinish => 'updateList'
I suppose this is fairly obvious, but I didn't realize it right away.