Joe Levi:
a cross-discipline, multi-dimensional problem solver who thinks outside the box – but within reality™

Set your user’s mouse cursor to ‘busy’ during an AJAX request using ASP.NET AJAX

To bring us all up to the same level, when an AJAX request is made the browser’s “loading” indicator (the ball, orb, “e,” “N,” globe, etc.) does NOT spin as it does when a full page is loading. While that’s probably okay, it leaves user wondering what’s going on. Luckily the status bar on most browsers will still present a percentage loaded bar for the AJAX request, but that’s way at the bottom of the browser (and Safari doesn’t have a status bar at the bottom) so the user may still be left wondering.

Most sites have some kind up update notification animation to let the user know that an update is occurring. Unfortunately for our users, this is left up to the site designer or page developer, and can even be absent entirely. This is the problem: update indicators are no longer something a user can depend on; their positioning, style, and even their presence is subject to change site-to-site… and even page to page.

One common form of letting a user know that a page is being loaded/updated (whether in web or local application context) is by changing the mouse cursor to “busy.” I’ve never quite understood why an AJAX request wouldn’t cause the user’s mouse cursor to toggle over to the “busy” state while the update is in process, then toggle back to “normal” when the request is complete. Granted, the rest of the page may (or may not) be accessible during the asynchronous update, but prompting the user with a status indication right at their mouse has always been a ubiquitous bit of UI, why not use that in a web application? Once one has decided that it’s a good idea, how does one accomplish that in ASP.NET AJAX?

First, create a javascript file (I called mine ajaxmousecursor.js and put it in a folder named js on the root of my project) which contains the following code:

var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(InitializeRequest);
prm.add_endRequest(EndRequest);
function InitializeRequest(sender, args)
{
$get(‘divPageContainer’).style.cursor = ‘wait’;
}
function EndRequest(sender, args)
{
$get(‘divPageContainer’).style.cursor = ‘auto’;
}

One item of note, ‘divPageContainer’ is the of the div that contains your page; our rules will only apply to the mouse while it’s in that div. If you use a different name for your container div use that instead; if you don’t use a page container div you might consider it, or fall back to the div of the content that you’re updating (I prefer the former).

Next, since we’re talking about ASP.NET AJAX, I’m assuming you already have a ScriptManager reference on your page, if not you’ll need one to use any ASP.NET AJAX or AJAXcontrolToolkit controls, but you don’t “need” one for this trick little snippit, but to keep everything in the context of ASP.NET AJAX I’ll show the proper usage in that environment (otherwise, just call the script using a script tag with a src reference).

<asp:ScriptManager ID=”ScriptManager1″ runat=”server”>
<Scripts>
<asp:ScriptReference path=”/js/ajaxmousecursor.js” />
</Scripts>
</asp:ScriptManager>

That’s it! Whenever your mouse is inside the page container div and an AJAX call is made the cursor will change to a “busy” or “wait” cursor while the request is executing and back to normal when the request completes.

UPDATE:

I was having some problems with MSIE throwing a JavaScript exception (but still working), so I’ve re-wrote a bit of the .js to handle this error, as well as handle any instances with the code is called on a page where the named div does not exist:

var prm = Sys.WebForms.PageRequestManager.getInstance();

if (prm) {
prm.add_initializeRequest(InitializeRequest);
prm.add_endRequest(EndRequest);
}

var oElement = document.getElementById(‘divPageContainer’);

function InitializeRequest(sender, args)
{
if (oElement) oElement.style.cursor = ‘wait’;
}

function EndRequest(sender, args)
{
if (oElement) oElement.style.cursor = ‘auto’;
}

Enjoy!

Sources: Encosia, AJAX.ASP.NET docs

Technorati Tags: ASP.NET, AJAX, ASP.NET AJAX, Status Indicator
Share

You may also like...

13 Responses

  1. mikedopp says:

    This rocks!

  2. Enzo says:

    Hi. I try your method but I succeded to make it works only without the use of a MasterPage.

    I tried to put in the masterpage the div with id=”Content” and your code but it dosn’t change the mouse icon when I use an UpdatePanel in a page that use that MasterPage ! Do you have an idea why?

  3. Joe says:

    @Enzo,

    This method should work with or without masterpages.

    The key here is that the entire page is wrapped within a div (I call mine divPageContainer). This div is NOT runat=server and doesn’t necessarily have to be within your asp.net

    tag.

    The code here changes the mouse cursor while it’s inside the named div (so you could modify the code to only show busy in a specific area, but there’s an AJAX Control Toolkit Extender that does that).

    I’d suggest you make a new masterpage and .aspx page to verify the code works, then apply that to you pre-existing documents.

    Let me know how it works for you.

    http://www.JoeLevi.com

  4. Enzo says:

    Thank you for your answer.
    I realize that it wasn’t a problem of MasterPage but of the fact that the button was in a panel with “GroupingText” defined. In fact I notice that if my pointer is inside a panel (ONLY if the “GroupingText” label is defined) it doesn’t change look. The same if I have an other asp element (ex, textbox) and my pointer is inside that element … but in this last case is less evident while in the case of a panel is much more bad!!

    Can you understand why and do you have any idea how to avoid it?

    ==================
    I look at the html generated in the two cases and I see the following:

    (1) [working] panel without “GroupingText” label

    HTML code generated:

    Update Me

    =======================================
    (1) [NOT working if mouse is inside panel]
    panel with “GroupingText” label

    HTML code generated:

    Test

    Update Me

    ======================
    It is the tag that make the cursor not change look if inside it!!!
    ======================

    In the following I put all the code so you can see the problem, if you are interested:

    Masterpage:

    Example master

    Script:

    /* ajaxmousecursor.js */
    var prm = Sys.WebForms.PageRequestManager.getInstance();

    if (prm) {
    prm.add_initializeRequest(InitializeRequest);
    prm.add_endRequest(EndRequest);
    }

    var oElement = document.getElementById(‘all’);

    function InitializeRequest(sender, args)
    {
    if (oElement) oElement.style.cursor = ‘wait’;

    // Get a reference to the element that raised the postback,
    // and disables it.
    $get(args._postBackElement.id).disabled = true;
    }

    function EndRequest(sender, args)
    {
    if (oElement) oElement.style.cursor = ‘auto’;

    // Get a reference to the element that raised the postback
    // which is completing, and enable it.
    $get(sender._postBackSettings.sourceElement.id).disabled = false;
    }

    Page:

    <%–

    –%>

  5. Enzo says:

    Masterpage:
    <!–

    Example master

    –>

  6. Enzo says:

    It seems that I cannot post aspx code … sorry!

  7. Enzo says:

    It is the fieldset tag that makes the cursor not work if you are inside the panel!

    ????

  8. Dave says:

    I’ve been working with many variations of this. I’m using with an ajax based popup which takes a second or two to display. Some kind of indicator is needed while this is going on so the user doesn’t keep clicking the button. The cursor doesn’t change until AFTER the box is displayed and then changes back. Hardly able to tell. How do I make the cursor change immediately after the button is clicked? If I put an alert in the javascript before changing the cursor, then the cursor will change before loading the popup is undertaken. It’s like I need to do a “DoEvents” before running the popup logic in order for this to function usefully. Any ideas?

  9. Dave says:

    Ok, I’m a little off by my last description. Apparently what is going on is: the mouseover cursor is the hand for this control which does not change after clicking the control and executing the above javascript. If you move the mouse outside to another area, the wait cursor then displays. How do I turn the hand into the wait cursor without moving the cursor to a different position? I appreciate the help!

  10. Alan says:

    Thanks you for this very helpful snippet and explanation. Instead of creating “divPageContainer” I simply refer to “form1” – the form where I have my ASP.NEt controls. I make sure that form1 is large enough to contain all my controls and it works perfectly.

  11. CynderR says:

    Thanks for this code 😉

    Here's a little adaptation of your idea, i wanted to have the wait cursor show up over every element on the page. (the css is the main thing that does the trick).

    To get my wait box working add this css

    .waitbox{
    position:fixed;
    width:100%;
    height:100%;
    z-index:100;
    top:0;
    left:0;
    cursor:wait;
    }

    these functions to your JS

    function showWaitBox(){
    var theDiv = document.createElement('div');
    theDiv = setClass(theDiv,”waitbox”);
    document.getElementById('waitBox').appendChild(theDiv);
    }
    function clearTag(tag) {
    //a simple script to empty a HTML object.
    while(tag.firstChild) tag.removeChild(tag.firstChild);
    }

    and this tag to your HTML (anywhere bottom is easiest.)

    <div id=”waitBox”></div>

    Then you can add showWaitBox() to any place you want to see the wait cursor.
    and you can remove it by calling clearTag(document.getElementById('waitBox'))

    Hope this helps someone.

  12. itai says:

    better put the “var oElement = document.getElementById(’divPageContainer’); ” statement in the functions, the element is not exist when this script runs.

    useful article.

  13. Ran says:

    Thanks for posting this script, it is a real must in some cases.

    I do however, have a little problem with it:
    assuming the ajax is triggered by clicking a button,
    the “busy” cursor will appear only if you move the cursor out of this button (tested on FF).

    Any idea ?

Leave a Reply to EnzoCancel reply