When designing web user interfaces with callbacks (aka “Ajax”), it’s important to provide visual cues that something is happening and advise the user to wait a second or two. People regard Google Suggest as the ultimate “Ajax” application. Google Suggest works lightening fast because they can afford fast hardware, and are able to search through their giant storage and deliver suggestions in under a second. For most of us it’s an unattainable dream, and we have to deal with very real latencies.
Under these circumstances users may get easily confused when, for example, they click a button but see no traditional browser response, such as a page postback or refresh. I think this aspect of “Ajaxy” applications gets overlooked very often. Ideally, you need to display a progress indicator before a callback is placed and hide it as upon response completion. The progress indicator I allude to may be simply an animated image like the famed MacOS spinning pizza of death.
For example, if you use the Telerik suite of callback controls, you display a progress indicator upon onRequestStart, and remove it on onReponseEnd:
<script type="text/javascript">
function onRequestStart() { ProgressIndicator.display(); }
function onResponseEnd() { ProgressIndicator.hide(); }
</script>
<radclb:CallbackButton id="TestButton" runat="server"
Text="(Your text goes here)"
DisableAtCallback="true"
AllowOtherCallbacks="false"
ClientEvents-OnRequestStart="onRequestStart"
ClientEvents-OnResponseEnd="onResponseEnd" />
ProgressIndicator is designed as a JavaScript singleton class with two public methods: display(anchorId) and hide(). You pass to display the id of an arbitrary element and it displays a progress indicator image on top of this element during callback.
For example, I developed a sample with four test cases. The sample imitates an “Ajax” callback by simply setting a timer. In the real world you’ll have an actual request/response sequence here.
My rule of thumb is to display a progress indicator on top of the calling control. I think it sends a clear message to the user that the action is being performed in response to the clicked control. This is exactly what happens when you click the check box, both buttons, or select a list item.
Since we use Telerik controls, I used their animated GIFs as visual cues. Depending on the dimensions of the covered element, ProgressIndicator picks an image of appropriate size. This is why you see a bar when you click Run test 1—it simply is not high enough to accommodate the larger image.
I’d like to also point out that if no anchorId is passed to the display method, the progress area is centered in the middle of the browser window. Click Run test 3 to see how it works.
Implementation Details
I liked Nikhil’s way of declaring private class members and accompanying “property setters” and “getters.” ProgressIndicator has two private instance variables, _anchorId and _inProgress, each with a pair of private getters and setters. Both display and hide are privileged methods and therefore can access private methods. See Private Members in JavaScript by Douglas Crockford to learn more about this.
Conclusion
The sample is a close-enough approximation of what we use in production, while the ProgressIndicator class itself is fully functional. Please note that in the sample you can kick off several tests at the same time. ProgressIndicator won’t allow re-entrancy while a callback is in progress, but the use of setTimeout in the sample produces a funky effect.
In a real-world scenario you need to decide whether you allow simultaneous callbacks or require them placed sequentially. For example, Telerik controls have a handy property, AllowOtherCallbacks, to configure this behavior. Personally, I prefer sequential callbacks.
I tested the sample in Mozilla, Opera, IE/Win 5.0, 5.5, 6.0. If you have any comments or suggestions, please speak up.