Topic: HOWTO: Implement a site-wide AJAX throbber by rewriting helpers

There's quite a few pieces of code going about that allow you to have a throbber with minimal difficulty (something to indicate to the user the system is working).  None of them, however, fulfilled my needs.  Grace (my AJAX webmail client) allows widgets (a partial that gets rendered to a specific div) to be dynamically added, and the user should be able to use standard Rails code to integrate them with system, which means that the throbber should work any time any link is clicked.  This meant that, for my purposes, I had to rewrite the definition of link_to_remote.

My new definition of link_to_remote is as follows (add it to app/helpers/application_helper.rb):

def link_to_remote(name, options = {}, html_options = {})
  options[:before] = "throb();" + options[:before].to_s
  options[:complete] = options[:complete].to_s + "; unthrob()"
  link_to_function(name, remote_function(options), html_options)
end

This appends a javascript method throb() to the beginning of the generated onClick, and the method unthrob() to the end of it.  We'd better write those methods then!  Add the following to public/javascripts/application.js:
//Start the throbber
function throb(){
  document.getElementById("throbber").innerHTML = "Loading . . .";
}

//Stop the throbber
function unthrob(){
  document.getElementById("throbber").innerHTML = "";
}


Obviously you want to replace the values innerHTML is set to to whatever you want your throbber to be (animated gifs being the obvious choice), but some text is good enough to demonstrate the principle.  Finally, add a div with the id "throbber" to your main layout (somewhere that won't get reloaded by AJAX calls), and Bob's your uncle!  All AJAX calls made with link_to_remote will cause the throbber to be displayed while they are working.  You can also extend this to other helpers as well (form_remote_tag, submit_to_remote and so on) for site-wide, DRY throbber goodness.

Last edited by Douglas (2007-01-22 21:19:07)

Re: HOWTO: Implement a site-wide AJAX throbber by rewriting helpers

Excellent tutorial! And fun too.

I'm curious how it works, I thought link_to_function behaved differently than link_to_remote? I haven't actually tried it so maybe I'm wrong.

One suggestion is to add a semicolon after the throb() function so appending more javascript won't cause a problem. You can shorten it a bit too:

def link_to_remote(name, options = {}, html_options = {})
  options[:before] = "throb();" + options[:before].to_s
  options[:complete] = "unthrob();" + options[:complete].to_s
  link_to_function(name, remote_function(options), html_options)
end

Railscasts - Free Ruby on Rails Screencasts

Re: HOWTO: Implement a site-wide AJAX throbber by rewriting helpers

The link_to_function call is the source code of the original link_to_remote.  Obviously I can't call link_to_remote again seeing as I've overwritten it.

Does to_s work on nil objects?  I must check that, the compressed version looks much nicer.

Also I didn't notice the lack of semi-colon breaks further javascript, good catch.

Edit: updated the original listing.  It also seems to make sense to put the unthrob call after any other javascript in :complete.

Edit 2: updated again using the compressed version.  Hooray for pretty code smile

Last edited by Douglas (2007-01-22 20:51:30)

Re: HOWTO: Implement a site-wide AJAX throbber by rewriting helpers

Douglas wrote:

The link_to_function call is the source code of the original link_to_remote.  Obviously I can't call link_to_remote again seeing as I've overwritten it.

You could make an alias of the method so you can reference it. I forgot the exact syntax but it's something like this:

alias :link_to_remote, :old_link_to_remote
def link_to_remote(name, options = {}, html_options = {})
  options[:before] = "throb();" + options[:before].to_s
  options[:complete] = options[:complete].to_s + ";unthrob()"
  old_link_to_remote(name, options, html_options)
end

Also, I added a semicolon before unthrob in case the complete parameter doesn't have it at the end. Not sure if you want to do that though.

Railscasts - Free Ruby on Rails Screencasts