16 May 2008 Providing User Feedback on Ajax calls in Rails
Following on from Tom’s post on Handling AJAX Errors using Prototype & Rails, I thought I’d take a look at how to ensure that all Ajax calls are subject to decent error handling – or any other sort of handling you want to do.
Towards the end of his post, Tom showed how he overrode form_remote_tag to include his error handling hooks. The only catch is that form_remote_tag isn’t the only way to trigger an Ajax call – there’s also form_remote_for, link_to_remote and a bunch other methods in ActionView::Helpers::PrototypeHelper.
You could override all of them if you wanted to, but it might just be easier to override the granddaddy of them all: remote_function. As far as I can tell, all of the PrototypeHelper methods use it, and you might even have to use it directly yourself for particularly sticky problems (that’s why it’s part of the public API). It’d look something like this in your helper class:
def remote_function_with_user_feedback(options) # .. Do extra stuff... remote_function_without_user_feedback(options) end alias_method_chain :remote_function, :user_feedback
Of course, that does beg the question: what exactly is the ‘extra stuff’?
Well, you could setup a callback that notifies the user if a server error occurs:
options[:failure] = (options[:failure] || '') + 'alert("An error has occured on the server. Please try again later."); '
Or you could even try out the more sophisticated network-outage detection code in Tom’s original blog entry.
Alternately, have you ever clicked a button in an Ajax app and been left wondering why nothing seems to be happening? Wouldn’t it be good if something started spinning to tell you that ‘stuff’s happening’? Well here’s how you could do it:
options[:before] = (options[:before] || '') + "$('spinner').src = '#{image_path "#active-spinner.gif"}';" options[:complete] = (options[:complete] || '') + "$('spinner').src = '#{image_path "#inactive-spinner.gif"}';"
Note that in each case, it’s important not to overwrite any existing Javascript callbacks that may have been provided to remote_function – instead we just concatenate our own Javascript code to them. Thanks to Tom for pointing this out.
It’s also worth remembering that you’re extending a pretty important Rails method here so make sure you get it right…and by that I mean make sure you’ve got some tests 🙂
Joshuab
Posted at 17:06h, 21 JuneInjecting the behavior through remote_function seems useful, but did you know Prototype already allows you to catch all ajax calls?
Ajax.Responders.register({
onCreate: function() {
if(Ajax.activeRequestCount>0)
show_progress_bar();
},
onComplete: function() {
if(Ajax.activeRequestCount==0)
hide_progress_bar();
}
});
leethal
Posted at 19:56h, 23 June(SUPER SECRET!)
Or, you can use jQuery and be unobtrusive about it, and handle errors in the global error callback for failed ajax requests. Yay!