Using RJS generator methods in raw JS

Written . Tagged Ajax, JavaScript, Ruby, Ruby on Rails.

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

1
2
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

1
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

1
2
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:

1
2
3
4
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.