RJS minus R
View blog reactions Written on April 24, 2007 by Chris Heald
RJS is a great little tool for interactively updating pieces of a page in response to some AJAX action, but it tends to fall short when you want to do anything beyond blinding dumping content into a page. Dan Webb has written a plugin called “MinusR” that basically flips RJS templates on their head. Instead of using Ruby generators to generate Javascript statements, you can write plain Javascript and are given a helper method to dump any Ruby statement to a properly escaped and encoded Javascript string. The example that Dan gives is something like this:
page << 'if (someClientSideVariable) {'
page['a'].replace_html :partial => 'thing'
page << '} else {'
page['b'].replace_html :partial => 'thong'
page << '}'
becomes:
if (someClientSideVariable) {
$('a').update(<%=js render(:partial => 'thing') %>);
} else {
$('b').update(<%=js render(:partial => 'thong') %>);
}
I’d certainly argue that the second example is cleaner.
In my own work, I’ve developed an RJS file using this which does in-page popup menus using Javascript. The RJS file looks something like this:
if(!$('xhr_popup')) {
new Insertion.Bottom('document_body', <%=js render( :partial => "/xhr_popup", :locals => {:partial => partial})%>);
new Draggable('xhr_popup');
tooltipifyElement($('xhr_popup_close_button'));
}
$('xhr_popup').update_function = function() {
var bHeight = document.getElementsByTagName("body")[0].getHeight() + 30;
$("background-fader").setStyle({height: bHeight + "px", top: 0});
Element.update('xhr_popup_content', <%=js render :partial => partial %>);
var offset = Position.page(document.getElementsByTagName("body")[0]);
var yPos = (parseInt(offset[1]) - 100) * -1;
$('xhr_popup').setStyle({top: yPos + "px"});
new Effect.Appear("background-fader", {duration: 0.4, from: 0.0, to: 0.6});
new Effect.Appear("xhr_popup", {from: 0, to: 1.0, duration: 0.4});
}
if ($('xhr_popup').visible()) {
new Effect.Fade('xhr_popup', {duration: 0.25, afterFinish: function() { $('xhr_popup').update_function(); }});
} else {
$('xhr_popup').update_function();
}
This allows me to:
- Create an element if it doesn’t exist
- Fade the element out if it exists and is visible
- Update the element’s content
- Fade in a background div that “disables” the background (ie, non-popup portion of the page) giving me an effectively modal dialog
- Fade in my updated element
While this same effect could be achieved using standard RJS, it would require certain things, such as pre-populating your template with a container for the popup and background, and wouldn’t have visibility-sensitive popup fading. With the Prototype library, writing cross-platform Javascript is extremely easy, and well worth your time if you’re looking to achieve any kind of advanced effect. And honestly, is
new Insertion.Bottom('document_body', <%=js render( :partial => "/xhr_popup", :locals => {:partial => partial})%>);
any harder than this?
page.insert :bottom, "document_body", render(:partial => "/xhr_popup", :locals => {:partial => partial});
Posted in 