191

Something as simple as:

$("#div").addClass("error").delay(1000).removeClass("error");

doesn't seem to work. What would be the easiest alternative?

serg
  • 109,619
  • 77
  • 317
  • 330

11 Answers11

389

You can create a new queue item to do your removing of the class:

$("#div").addClass("error").delay(1000).queue(function(next){
    $(this).removeClass("error");
    next();
});

Or using the dequeue method:

$("#div").addClass("error").delay(1000).queue(function(){
    $(this).removeClass("error").dequeue();
});

The reason you need to call next or dequeue is to let jQuery know that you are done with this queued item and that it should move on to the next one.

PetersenDidIt
  • 25,562
  • 3
  • 67
  • 72
  • 3
    I like this option because it makes it easy to pass a reference to the jquery object thats used in the queued function, so it can be used in a more generic context (without hard coded names). – GrandmasterB Nov 01 '12 at 05:36
  • 5
    Why do we need "next"? Can we do $("#div").addClass("error").delay(1000).queue(function(){ $(this).removeClass("error"); }); Seems more elegant? – Vennsoh Dec 12 '13 at 10:50
  • @Vennsoh You don't need to pass a 'next' queue item. You may choose to use the dequeue() method instead: http://api.jquery.com/dequeue/ – gfullam Feb 05 '14 at 18:37
52

AFAIK the delay method only works for numeric CSS modifications.

For other purposes JavaScript comes with a setTimeout method:

window.setTimeout(function(){$("#div").removeClass("error");}, 1000);
Jasper
  • 1,971
  • 19
  • 34
  • 14
    +1: Don't use Jquery for Jquery's sake. There are simple javascript solutions to many problems. – Joel Mar 24 '10 at 17:56
  • 1
    +1: Just the same as first comment. Simple JS also works fine some times. – wowpatrick Jun 11 '11 at 13:53
  • 1
    +1 for simplicity, but also +1'ed the accepted answer - as it pointed me out that the .queue() actually passes continuation object that must be called manually (the 'next()'). I've spent half of hour wondering why my chain of parameterless callbacks execute only the first one -- many examples on other sites use a single delay in chain and a parameterless callback, which is a bit misleading oversimplification of that mechanism – quetzalcoatl Dec 28 '11 at 17:58
  • 2
    Just a pedant note: setTimeout comes from the browser's window object (BOM). JavaScript (understood as ECMA Script) doesn't have that method. – corbacho Oct 05 '12 at 08:47
11

I know this this is a very old post but I've combined a few of the answers into a jQuery wrapper function that supports chaining. Hope it benefits someone:

$.fn.queueAddClass = function(className) {
    this.queue('fx', function(next) {
        $(this).addClass(className);
        next();
    });
    return this;
};

And here's a removeClass wrapper:

$.fn.queueRemoveClass = function(className) {
    this.queue('fx', function(next) {
        $(this).removeClass(className);
        next();
    });
    return this;
};

Now you can do stuff like this - wait 1sec, add .error, wait 3secs, remove .error:

$('#div').delay(1000).queueAddClass('error').delay(2000).queueRemoveClass('error');

Sandbox
  • 171
  • 1
  • 5
6

jQuery's CSS manipulation isn't queued, but you can make it executed inside the 'fx' queue by doing:

$('#div').delay(1000).queue('fx', function() { $(this).removeClass('error'); });

Quite same thing as calling setTimeout but uses jQuery's queue mecanism instead.

warpdesign
  • 727
  • 2
  • 7
  • 17
  • This works for me better then accepted answer (calls not repeats if there is a transition transformation in class). – vatavale Mar 09 '19 at 15:45
6

Of course it would be more simple if you extend jQuery like this:

$.fn.addClassDelay = function(className,delay) {
    var $addClassDelayElement = $(this), $addClassName = className;
    $addClassDelayElement.addClass($addClassName);
    setTimeout(function(){
        $addClassDelayElement.removeClass($addClassName);
    },delay);
};

after that you can use this function like addClass:

$('div').addClassDelay('clicked',1000);
user6322596
  • 61
  • 1
  • 1
  • 1
    and if you want to add chaining support, read te basics about plugin creation, or simply add `return this` to the function... – user6322596 May 11 '16 at 21:21
2

Delay operates on a queue. and as far as i know css manipulation (other than through animate) is not queued.

prodigitalson
  • 60,050
  • 10
  • 100
  • 114
2

delay does not work on none queue functions, so we should use setTimeout().

And you don't need to separate things. All you need to do is including everything in a setTimeOut method:

setTimeout(function () {
    $("#div").addClass("error").delay(1000).removeClass("error");
}, 1000);
Ghasem
  • 14,455
  • 21
  • 138
  • 171
  • You don't have to use delay() with setTimeout(). – MattYao Feb 06 '19 at 03:53
  • @MattYao I don't think you get the idea. If you dont use setTimeout, then that delay wont work – Ghasem Feb 06 '19 at 04:32
  • 1
    The solution doesn't need both to work together. Either use delay() with queue() in jQuery or simply use setTimeout() can solve the problem. I am not saying your answer is wrong. – MattYao Feb 06 '19 at 04:35
0

Try this:

function removeClassDelayed(jqObj, c, to) {    
    setTimeout(function() { jqObj.removeClass(c); }, to);
}
removeClassDelayed($("#div"), "error", 1000);
0

Try this simple arrow funtion:

setTimeout( () => { $("#div").addClass("error") }, 900 );

csandreas1
  • 2,026
  • 1
  • 26
  • 48
0

Another way...

$("#div").addClass("error"); 
setTimeout(function () { $("#div").removeClass("error"); }, 1000);
-1
$("#div").addClass("error").show(0).delay(1000).removeClass("error");

Thanks me later.

Shabbir Vaghela
  • 224
  • 2
  • 8