11

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.

ripper234
  • 222,824
  • 274
  • 634
  • 905
  • 1
    If you only have the promise object (and no access to the original deferred), then it should be impossible to do that. The idea of a promise is to be able to listen to the deferred being resolved or reject, without the resolve/reject functionality. What you can do is create a promise wrapper that exposes the original promise functons, but all callbacks are binded with a wrapping function that listens to some kind of flag to avoid triggering the callback if the deferred is flagged as canceled. – Germán Enríquez Mar 08 '12 at 01:30
  • almost, you actually just want to create a deferred and manually reject or resolve it how you see fit. – Patrick Lee Scott Apr 17 '12 at 14:44

4 Answers4

4

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.

peter
  • 185
  • 5
2

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

aymericbeaumet
  • 6,853
  • 2
  • 37
  • 50
Paul
  • 12,392
  • 4
  • 48
  • 58
  • Well, I saw `remove(), but I was wondering if there's a way to do it without removing the actual element. Edited question. – ripper234 Mar 08 '12 at 00:17
  • 1
    Yea, having to remove the element from the dom does not seem ideal. Was the only way I could get it to work. Best of luck in your search for a better solution. – Paul Mar 08 '12 at 02:31
1

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.

Patrick Lee Scott
  • 8,217
  • 3
  • 36
  • 42
1

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

JayC
  • 7,053
  • 2
  • 25
  • 41
  • Of course, the biggest thing I'm curious about is what is supposed to happen to the animations once you reject the promise? – JayC Mar 08 '12 at 00:49
  • A bit clunky syntax ... I was hoping for a way to actually cancel a promise ... there might not be a way in the current implementation. – ripper234 Mar 08 '12 at 09:25