116

I am sure I read about this the other day but I can't seem to find it anywhere.
I have a fadeOut() event after which I remove the element, but jQuery is removing the element before it has the chance to finish fading out.
How do I get jQuery to wait until the element had faded out, then remove it?

joe_young
  • 4,107
  • 2
  • 27
  • 38
uriDium
  • 13,110
  • 20
  • 78
  • 138

4 Answers4

194

With jQuery 1.6 version you can use the .promise() method.

$(selector).fadeOut('slow');
$(selector).promise().done(function(){
    // will be called when all the animations on the queue finish
});
Reinaldo Junior
  • 2,387
  • 1
  • 15
  • 15
  • 5
    This is redundant for most jQuery animations as there are callback args on most methods, but using `promise()` or `when()` and `done()` you can leverage some very cool behaviour from 3rd party methods, or even your own. +1 for meantioning `.promise()`! – stuartc Apr 05 '12 at 08:57
  • 4
    Haven't heard this before, just saved my butt. – prismspecs Jun 26 '12 at 14:58
  • 1
    in my case, I was trying to access the current animation of an element that was happening somewhere else in my code, and thus I didn't have access to it's callback. +1 – Kristian Jul 26 '12 at 23:11
  • 13
    Using promise() also allows you to set up a single callback for when everything's done. If you call fadeOut() on a set of 10 things, there will be one callback for each thing with 'this' set to the appropriate scope. If you only want to fire once, this function is really helpful. Also: If you animate on a selector that turns out to match zero elements, the normal callback will never fire. Promise() will fire at the end no matter what. – zslayton Oct 11 '12 at 16:21
  • Thanks. This saved me a lot of time :D – Doan Cuong Apr 22 '13 at 06:38
  • +1, I've never heard of the `.promise()` function, and it helped me in my case – Tony Dec 03 '13 at 18:55
  • This is an excellent solution in cases where a separate event callback might need to wait to take a particular action on an element that another event could be interacting with. +1, this saved me a lot of heartache. – maiorano84 May 07 '14 at 14:37
  • 6
    You can also chain it like this: `$(selector).fadeOut('slow').promise().done(function(){...});` – Syclone Jul 25 '14 at 22:59
  • I tried using ES6 promises, like `Promise.resolve($(selector).fadeOut("slow")).then(function() {...});` but for some reason it seems to jump the gun by a fraction of a second, not waiting until the very end – binaryfunt Dec 08 '17 at 13:41
  • Much thanx for this! Attempting to draw a canvas object at a Complete callback for slideUp/Down hangs the browser, stack bombing, apparently. I always find the most obscure anomalies :^/ – yapdog Mar 19 '20 at 07:49
177

You can specify a callback function:

$(selector).fadeOut('slow', function() {
    // will be called when the element finishes fading out
    // if selector matches multiple elements it will be called once for each
});

Documentation here.

Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
  • Bingo. I thought it was that but what I needed to do was put my entire function in there not just the remove part. P.S. If any one is interested the book I read it in and have now found again is Learning JQuery - Better Interaction and Design. Thanks again – uriDium Jun 30 '09 at 20:23
  • If someone has old jQuery, then this "animation done callback" bug was a nasty one: http://bugs.jquery.com/ticket/5684 – JustAMartin May 23 '14 at 16:03
  • This actually solves quite a delicate problem with fading - if you have any kind of CSS transition on the element, the `fadeIn()` function doesn't work properly. You can combat it by doing: `$(this).addClass('disabled-transitions');` and right after that `$(this).fadeIn(500, function() {$(this).removeClass('disabled-transitions');});` – tomashauser Apr 16 '21 at 12:23
10

You can as well use $.when() to wait until the promise finished:

var myEvent = function() {
    $( selector ).fadeOut( 'fast' );
};
$.when( myEvent() ).done( function() {
    console.log( 'Task finished.' );
} );

In case you're doing a request that could as well fail, then you can even go one step further:

$.when( myEvent() )
    .done( function( d ) {
        console.log( d, 'Task done.' );
    } )
    .fail( function( err ) {
        console.log( err, 'Task failed.' );
    } )
    // Runs always
    .then( function( data, textStatus, jqXHR ) {
        console.log( jqXHR.status, textStatus, 'Status 200/"OK"?' );
    } );
kaiser
  • 21,817
  • 17
  • 90
  • 110
  • 2
    This part of this answer using `$.when()` does not work because `myEvent()` does not return a promise and `$.when()` expects you to pass it one or more promises for it to do its job. – jfriend00 Nov 08 '16 at 22:31
6

if its something you wish to switch, fading one out and fading another in the same place, you can place a {position:absolute} attribute on the divs, so both the animations play on top of one another, and you don't have to wait for one animation to be over before starting up the next.

Samin
  • 610
  • 3
  • 11
  • 22