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

14

75

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?

Clifton answered 11/11, 2009 at 22:10 Comment(5)
Chrome: This did it for me: https://mcmap.net/q/270656/-jquery-wait-cursor-while-loading-html-in-divMoats
As noted below by @j-allen, this issue is fixed in Chrome v50+ when the Developer Tools/Console is closed.Leoraleos
Despite the bugs in Chrome, I found a solution, which I describe in my answer below.Sihon
TLDR; Most important thing to know (even 13 years later) is that if you have devtools open it won't revert back to auto until you move the mouse. You can filter css properties by 'cursor' and watch it change to the correct value, but nothing will happen. It's probably related to the different cursor logic required for highlighting elements in devtools mode.Cello
@Cello For me (in Firefox 114) it's precisely the opposite. When the devtools are open the cursor gets correctly updated without movement (even in fullscreen) but when in fullscreen with DevTools closed the cursor only updates if it's not inside an imaginary diamond shape with its corners at the screen edge centers, so if the cursor is close to the coners it updates but on the same element closer to the center it fails to update for me.Roadstead
G
39

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

Giaour answered 18/11, 2009 at 14:27 Comment(11)
Bug reported in 2009, and still unconfirmed. Sad.Lula
thanks for the links. The first link has some useful comments, including #87 (code.google.com/p/chromium/issues/detail?id=26723#c87) which is the workaround I'm now usingArcheozoic
This code works for me. myDiv.scrollLeft +=1; myDiv.scrollLeft -1; code.google.com/p/chromium/issues/detail?id=26723#c32Tableware
For people coming across this now, although the bug was apparently fixed in 2013, it still sometimes occurs when dev tools is open (see the comments on the chromium bug 26723 from Dec 2016). So, close dev tools like your users will have, and then all good :)Countless
@TimMalone This is the specific issue for the dev tools thing. bugs.chromium.org/p/chromium/issues/detail?id=676644Cyanogen
@TimMalone WOW. Thanks.Tabriz
Still happening in 2017/08/20 chrome 60, with or without dev tools openPenang
Still happening for me on v70.0.3538.77 - wow this is really a long time bug. Same as OP, it works fine on FF/IE it is just Chrome that doesn't update cursor until the mouse is moved.Rachelrachele
Also seeing this bug on v70.0.3538.7 when devtools is open. Closing and opening devtools again sorts out the problem.Determinate
I'm doing this with react, setting the body to "grab". It doesn't update even while moving, only when i rest and do mouse up. At this point it should actually be "default" and it shows in the dev tools, but not in the view. Closing the devtools just straight up fixes the issue!Unsubstantial
2023 still happening in latest Chrome, I'm gonna switch to farming with you pplOften
M
38

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/

Mccurdy answered 1/3, 2011 at 21:47 Comment(4)
Korayem - +1. nice clean approach. i nicked it as a replacement for a rather messy implementation that i had cobbled together. thanks!! ;-)Rawinsonde
for my use case, I had to put this logic into a setTimeout of 1 millisecond to get it to take effectPrintmaking
This doesn't actually answer the question. If you don't move the mouse, the cursor doesn't change back to auto when you remove the class.Archeozoic
I like this solution, but I needed to bind the event to $(document), and then add the class to $('html) to get it to work.Retiary
E
30

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.

Epilate answered 20/5, 2016 at 16:30 Comment(9)
Ha, wouldn't have thought of closing developer tools. Thanks!Barthol
That is the key: close developer tools!Naaman
still not fixed in chrome 60Penang
just to be clear its not fixed if you reload the page i.e. location.reload(); really annoying... so in the ajax call when done do location.reload(); and the cursor will be wrong.Penang
Not fixed in 63.0.3239.108 (Official Build) (64-bit) as well :(Robins
A few tips: right click on the refresh button for different options. And see the Memory tab to check if the Memory gets lower when you refresh. It seems memory can be kept between reloads until the tab is closed.Allysonalma
Why is this still a thing?! I was losing my mind trying to figure out why my code wasnt working. Closed devtools and it worked right awayChap
Still not fixed in Chrome v100.Ethyne
2022, solution on https://mcmap.net/q/268983/-getting-the-browser-cursor-from-quot-wait-quot-to-quot-auto-quot-without-the-user-moving-the-mouse works, just close the dev-toolsIndicant
Z
7

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..

Zeitler answered 29/11, 2013 at 12:0 Comment(1)
And make sure the development tools are closed!Naaman
S
3

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.

Sihon answered 5/10, 2018 at 12:22 Comment(6)
Solution does not work for me on Chrome 70. The cursor stays as wait cursor until the mouse is moved.Rachelrachele
@PhilB Strange. It is working for me on Chrome 70.0.3538.77 on Windows 10. I have also successfully deployed this solution across dozens of environments including both Windows and MacOS with no such bug report yet.Sihon
I'm on Windows 7, if that could make some difference? :/Rachelrachele
@PhilB It may well do, perhaps hence the variety of solutions. I will keep an eye open for thisSihon
Ok I did a little more testing and it seems (as other mentioned) that I can only reproduce the issue with dev tools open. Good for me I guess. Solution ok anyways. :)Rachelrachele
Yes, this works only with the dev-tools closed.Indicant
T
1

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 :(

Touched answered 21/6, 2013 at 6:38 Comment(0)
K
1

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.

Kafiristan answered 23/6, 2016 at 14:42 Comment(0)
B
0

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

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

Buster answered 11/11, 2009 at 22:15 Comment(1)
Tried that. Tried lots of alterations. None of them were sufficient kicks to Chrome or Safari. Seems dumb. Why would the user want to touch the mouse if the cursor is showing wait?Clifton
M
0

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);
});

}
Mog answered 2/4, 2013 at 8:6 Comment(0)
B
0

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' ) } )
Byyourleave answered 25/12, 2014 at 7:27 Comment(0)
M
-1

Try using the correct css value for the cursor property:

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

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

Maxa answered 12/11, 2009 at 2:3 Comment(1)
Yeah, sorry. That's a typo. I am using (and having trouble with) "wait", not "busy".Clifton
P
-1

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.

Protostele answered 18/11, 2009 at 14:32 Comment(2)
I've tried many funky things, and the browsers seem to ignore them all. But if I get time, I'll try yours.Clifton
I have the same problem with a full size overlay too, and the cursor doesn't change, when not moved.Indicant
C
-2

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.

Cagey answered 4/2, 2011 at 13:21 Comment(0)
K
-3

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

Kindergarten answered 27/11, 2012 at 23:59 Comment(2)
Applying that to ALL elements?? Not gonna happen. And doesn't fix the bug either.Activator
This doesn't overcome the bug.Archaean

© 2022 - 2024 — McMap. All rights reserved.