Question

How can I cancel a promise without removing the element from the DOM?

fiddle

I ran this code:

$("#box")
  .delay(2000)
  .show("slow")
  .delay(2000)
  .promise()                            
  .then(function(){log("Done");});

After this, is there a way to cancel the promise? Both clearQueue() and stop(true) didn't work, because it's not an animation that I'm trying to cancel. I saw that remove() should do it ... but I only want to stop the promise, not remove the entire element.

Was it helpful?

Solution

Good news. Since yesterday you can cancel your promise.

I published the new version of my small plugin jquery-timing that provides two methods amongst many others called .wait() and .unwait().

var deferred = $("#box").delay(2000).show("slow").delay(2000).promise();
$.wait(deferred, function(){ log("Done"); });

If you then want to unregister the callback:

$.unwait();

These static versions of wait and unwait also support an optional group name to not cancel any handler but only a specific set.

Besides that you can do a lot more smart stuff like:

$('#box').wait(deferred).addClass('ready');

or the whole code in one chain, without unwait option:

$("#box").delay(2000).show("slow")
  .delay(2000).join(function(){log("Done");})).addClass('ready');

or the same even shorter with option to cancel the two pauses:

$("#box").wait(2000).show("slow",$)
  .wait(2000, function(){log("Done");})).addClass('ready');

Just see the docs, examples, and API what fits best for you.

OTHER TIPS

I believe you can use $('#box').remove();

From the jQuery documentation here: http://api.jquery.com/promise/

The returned Promise is linked to a Deferred object stored on the .data() for an element. Since the .remove() method removes the element's data as well as the element itself, it will prevent any of the element's unresolved Promises from resolving. If it is necessary to remove an element from the DOM before its Promise is resolved, use .detach() instead and follow with .removeData() after resolution."

I don't suppose you'd want something like http://jsfiddle.net/2cq8M/ ? I'm involving two promises (one just to handle the case at the end of the set of animations, the other to resolve or reject as needed).

You want to use a deferred in this case instead of a promise, however, you can use the promise of the animation to resolve the deferred.

http://jsfiddle.net/LG9eZ/9/

var stopDone = true;

function log(msg) {
    $(".debug").append(new Date() + " - " + msg + "<br/>");
}

log("Starting");

var boxAnimation = new $.Deferred();
boxAnimation.done(function() {
    log("Done");
});
boxAnimation.fail(function() {
    log("Stopped");
});


$("#box").delay(2000).show("slow").delay(2000).promise().then(function() {
    boxAnimation.resolve(); // when all the animations are done, resolve the deferred.
}); 


if (stopDone)
{
    boxAnimation.reject();
}

As a side note, deferreds can only rejected or resolved once. Once they are rejected or resolved, you cannot change their state.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top