Ajax Busy Indicators Part 2

Just a follow-up to my last post on Ajax busy indicators, where I described how to implement a single image/callback to indicate the status of all the Ajax requests on your site. The limitation was that the image had to always be placed in a pre-defined spot on the page, which is less than desirable. This can be overcome by dynamically changing the position of your image based on which link/button was pressed. Consider the following javascript:

function setBusyNextTo(link) {
  linkPosition = Position.cumulativeOffset(link);
  linkDimensions = Element.getDimensions(link);
  imageHeight = Element.getDimensions('busy_img').height;
  x = linkPosition[0] + linkDimensions.width;
  y = linkPosition[1] + (linkDimensions.height / 2) - (imageHeight / 2);
  $('busy_img') = y + "px";
  $('busy_img').style.left = x + "px";

You can hook this up to your ajax links (or buttons) using the after callback:

<%= link_to_remote("Action", {
  :url   => {:action => "ajax_action"},
  :after => "setBusyNextTo(this)"})%>

This will place the activity indicator directly to the right of the link that was clicked. The code in my previous post will take care of actually displaying the indicator (via a generic callback.) Note that this code makes no assumptions as to the physical size of the indicator image - The image will be vertically centered next to the link. This makes it possible to try out a bunch of different indicators by simply changing the src attribute of your indicator's image tag. The vertical positioning will be taken care of, but the horizontal positioning may be a bit trickier. You will have to make sure that your link or button has enough empty space to the right of it to avoid placing your indicator on top of something.

This idea can be taken a step further by adding the positioning functionality to our links and buttons unobtrusively (say, in the body's onload handler.) This can be accomplished with the following beautiful piece of javascript:

$$("a").each(function(anchor) {
  anchor.onclick= function() {setBusyNextTo(this)};

Be careful with this method though, as this will only affect those dom elements that were originally created at the last browser page load (as opposed to the last javascript dom manipulation.)

blog comments powered by Disqus