Getting the browser cursor from "wait" to "auto" without the user moving the mouse

48k views Asked by At

I use this jQuery code to set the mouse pointer to its busy state (hourglass) during an Ajax call...

$('body').css('cursor', 'wait');

and this corresponding code to set it back to normal...

$('body').css('cursor', 'auto');

This works fine... on some browsers.

On Firefox and IE, as soon as I execute the command, the mouse cursor changes. This is the behavior I want.

On Chrome and Safari, the mouse cursor does not visibly change from "busy" to "auto" until the user moves the pointer.

What is the best way to get the reluctant browsers to switch the mouse pointer?

14

There are 14 answers

11
user213788 On BEST ANSWER

It is a bug in both browsers at the moment. More details at both links (in comments as well):

http://code.google.com/p/chromium/issues/detail?id=26723

and

http://code.google.com/p/chromium/issues/detail?id=20717

1
Sergiu On

I got inspired from Korayem solution.

Javascript:

jQuery.ajaxSetup({
    beforeSend: function() {
       $('body').addClass('busy');
    },
    complete: function() {
       $('body').removeClass('busy');
    }
});

CSS:

.busy * {
    cursor: wait !important;
}

Tested on Chrome, Firefox and IE 10. Cursor changes without moving the mouse. "!important" is needed for IE10.

Edit: You still have to move cursor on IE 10 after the AJAX request is complete (so the normal cursor appear). Wait cursor appears without moving the mouse..

0
Arun George On

Hey Guys, I have a nitty gritty solution which works on all browsers. Assumption is protoype library is used. Someone can write this as plain Javascript too. The solution is to have a div on top of all just after you reset the cursor and shake it a little bit to cause the cursor to move. This is published in my blog http://arunmobc.blogspot.com/2011/02/cursor-not-changing-issue.html.

4
Korayem On

I would rather do it more elegantly like so:

$(function(){  
  $("html").bind("ajaxStart", function(){  
     $(this).addClass('busy');  
   }).bind("ajaxStop", function(){  
     $(this).removeClass('busy');  
   });  
});

CSS:

html.busy, html.busy * {  
  cursor: wait !important;  
}  

Source: http://postpostmodern.com/instructional/global-ajax-cursor-change/

1
PetersenDidIt On

Try using the correct css value for the cursor property:

$('body').css('cursor','wait');

http://www.w3schools.com/CSS/pr_class_cursor.asp

1
SLaks On

I don't think you'll be able to do it.

However, try changing the scroll position; it might help.

2
Adam Raney On

I haven't tried this, but what about if you create a transparent div that is absolutely positioned and fills the viewport just before changing the CSS. Then, when the css is changed on the body, remove the div. This might trigger a mouseover event on the body, which might cause the cursor to update to the latest CSS value.

Again, I haven't tested this, but it's worth a shot.

6
Ninjakannon On

Working solution on CodeSandbox

Some of the other solutions do not work in all circumstances. We can achieve the desired result with two css rules:

body.busy, .busy * {
  cursor: wait !important;
}

.not-busy {
  cursor: auto;
}

The former indicates that we are busy and applies to all elements on the page, attempting to override other cursor styles. The latter applies only to the page body and is used simply to force a UI update; we want this rule to be as non-specific as possible and it doesn't need to apply to other page elements.

We can then trigger and end the busy state as follows:

function onBusyStart() {
    document.body.classList.add('busy');
    document.body.classList.remove('not-busy');
}

function onBusyEnd() {
    document.body.classList.remove('busy');
    document.body.classList.add('not-busy');
}

In summary, although we have to change the cursor style to update the cursor, directly modifying document.body.style.cursor or similar does not have the intended effect, on some engines such as Webkit, until the cursor is moved. Using classes to affect the change is more robust. However, in order to reliably force the UI to update (again, on some engines), we have to add another class. It seems removing classes is treated differently from adding them.

0
AudioBubble On

As of jquery 1.9 you should ajaxStart and ajaxStop to document. They work fine for me in firefox. Have not tested in other browsers.

In CSS:

html.busy *
{
   cursor: wait !important;
}

In javaScript:

// Makes the mousecursor show busy during ajax 
// 
$( document )

   .ajaxStart( function startBusy() { $( 'html' ).addClass   ( 'busy' ) } )     
   .ajaxStop ( function stopBusy () { $( 'html' ).removeClass( 'busy' ) } )
0
pmrotule On

First of all, you should be aware that if you have a cursor assigned to any tag within your body, $('body').css('cursor', 'wait'); will not change the cursor of that tag (like me, I use cursor: pointer; on all my anchor tag). You might want to look at my solution to this particular problem first : cursor wait for ajax call

For the problem that the cursor is only updated once the user move the mouse on webkit browsers, as other people said, there is no real solution.

That being said, there is still a workaround if you add a css spinner to the current cursor dynamically. This is not a perfect solution because you don't know for sure the size of the cursor and if the spinner will be correctly positioned.

CSS spinner following the cursor: DEMO

$.fn.extend(
{
    reset_on : function(event_name, callback)
    { return this.off(event_name).on(event_name, callback); }
});

var g_loader = $('.loader');

function add_cursor_progress(evt)
{
    function refresh_pos(e_)
    {
        g_loader.css({
            display : "inline",
            left : e_.pageX + 8,
            top : e_.pageY - 8
        });
    }
    refresh_pos(evt);
    var id = ".addcursorprog"; // to avoid duplicate events

    $('html').reset_on('mousemove' + id, refresh_pos);

    $(window).
    reset_on('mouseenter' + id, function(){ g_loader.css('display', 'inline'); }).
    reset_on('mouseleave' + id, function(){ g_loader.css('display', 'none'); });
}

function remove_cursor_progress(evt)
{
    var id = ".addcursorprog";
    g_loader.css('display', 'none');

    $('html').off('mousemove' + id);
    $(window).off('mouseenter' + id).off('mouseleave' + id);
}

$('.action').click(add_cursor_progress);
$('.stop').click(remove_cursor_progress);

You will need to check if it is a touch device as well var isTouchDevice = typeof window.ontouchstart !== 'undefined';

In conclusion, you better try to add in your page a static spinner or something else that shows the loading process instead of trying to do it with the cursor.

2
Dan Hunex On

$('*').css('cursor','wait'); will work everywhere on the page including links

0
cestar On

HERE is my solution:

function yourFunc(){

$('body').removeClass('wait'); // this is my wait class on body you can $('body').css('cursor','auto');
$('body').blur();
$('body').focus(function(e){
$('body')
 .mouseXPos(e.pageX + 1)
 .mouseYPos(e.pageX - 1);
});

}
0
Felix On

Korayem's solution works for me in 100% cases in modern Chrome, Safari, in 95% cases in Firefox, but does not work in Opera and IE.

I improved it a bit:

$('html').bind('ajaxStart', function() {
    $(this).removeClass('notbusy').addClass('busy');
}).bind('ajaxStop', function() {
    $(this).removeClass('busy').addClass('notbusy');
});

CSS:

html.busy, html.busy * {
    cursor: wait !important;
}

html.notbusy, html.notbusy * {
    cursor: default !important;
}

Now it works in 100% cases in Chrome, Safari, Firefox and Opera. I do not know what to do with IE :(

9
J. Allen On

I believe this issue (including the mousedown problem) is now fixed in Chrome 50.

But only if you are not using the developer tools!!

Close the tools and the cursor should immediately respond better.