0

I'm building a game with move.js for animation, but it takes too long so when the player click on the right solution it displays the winning message before the right solution change it's color, so I used deferred object to fire an event and catch it when the animation ends.

Here's my code:

var deferred = new $.Deferred();
click(e);
//show message when game is over
$.when(deferred).then(function(){
    if (this.checkIfWin()){
        alert('you won !');
        this.nextLevel();
    }
});
function click(e){
    move(e)
    .set('background-color','black')
    .delay('0.1s')
    .end();
    deferred.notify();
}

but it's not notified and the message doesn't show up.What am I missing here ?

Ammar Lakis
  • 79
  • 2
  • 11

2 Answers2

2

Because animations in javascript are asynchronous (they run via timers), the only way to know when they are done is to hook into some sort of completion callback or completion notification.

I don't know move.js myself, but it looks like you can get such a callback by supplying a callback to the .end(fn) method. But, you will also have to fix your code because this in this.checkIfWin() will not be the right value in either of these code blocks. I don't know what you want it to be (since you don't show that part of your code), but you will have to refer to some other object besides this. In any case, here's the general structure of the code both with and without the use of a deferred.

var deferred = new $.Deferred();

// your code was using this here 
// so I will save a reference to it that can be used later, but there is
// probably a better way to do this if I could see the rest of your code
var obj = this;

click(e);

//show message when game is over
deferred.promise().then(function(){
    if (obj.checkIfWin()){
        alert('you won !');
        obj.nextLevel();
    }
});

function click(e){
    move(e)
    .set('background-color','black')
    .delay('0.1s')
    .end(function() {
        deferred.resolve();
    });
}

In this case, it doesn't look like you really need to use the deferred as you could just put the completion code right in the callback:

// your code was using this here 
// so I will save a reference to it that can be used later, but there is
// probably a better way to do this if I could see the rest of your code
var obj = this;

click(e);

function click(e){
    move(e)
    .set('background-color','black')
    .delay('0.1s')
    .end(function() {
        if (obj.checkIfWin()){
            alert('you won !');
            obj.nextLevel();
        }
    });
}
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Why the downvote? This is how you know when move.js animations are done. – jfriend00 Jul 26 '14 at 16:23
  • -1 . Does not apply to question relevant to `deferred.notify` ; similar pattern utilized by this user . Question does not ask for `deferred.promise()` callback . Thanks – guest271314 Jul 26 '14 at 16:24
  • `this` within the `.then()` callback , at top example , would refer to the `deferred` object itself , unless cast to some other object ? Thanks – guest271314 Jul 26 '14 at 16:29
  • @guest271314 - The question is how to know when the animation is done. This is the ONLY answer here that actually answers that question. The action can be triggered with or without promises. I did not use `.notify()` because the promise standards are removing that capability and thus it is generally not advisable to code with it. I solved the issue two other ways. If the OP really wants to use .notify, then can still do that using this scheme. – jfriend00 Jul 26 '14 at 16:29
  • @guest271314 - yes I know about the issue with `this`. That's why I've explained in my post that the OP will have to use a reference to some other object there. They don't show enough of their code for me to know exactly how to recommend that. My code is fully annotated to that effect. – jfriend00 Jul 26 '14 at 16:30
  • Was unaware of `deferred.notify` being removed from jquery ? Agree with want of clarity at OP . 1st "downvote" at SO. Will upvote your Answer after this comment . Either piece should work , given pieces provided at OP - as `notify` called _after_ `.end()` - also , don't have `html` , animation details to determine if _either_ Answer actually works . Thanks – guest271314 Jul 26 '14 at 16:43
  • "I did not use .notify() because the promise standards are removing that capability and thus it is generally not advisable to code with it. " . Link to documentation regarding `deferred.notify` removal from jquery ? Thanks – guest271314 Jul 26 '14 at 19:31
  • @guest271314 - I don't know if jQuery will remove/change `.notify()` or when. It is being removed from the promise standards (to be done a different way) and I assume that eventually jQuery will follow those specifications because they will want to be able to interoperate with promises and notifications that come from outside of jQuery. It's not an imminent thing, just something I picked up by reading what the folks who work on the promise standards write and do, so something I figured I would avoid until it's being done a way that is not as likely to be changed. – jfriend00 Jul 26 '14 at 21:28
  • fwiw, from humble perspective, `jquery.deferred` one of most versatile , interesting portions of jquery . If can share documentation , lists , links to adjustments to pure js promise standards , would be appreciated . Could not find notes on such a change via search engines . btw, if possible , please (re-)view updated / edited post ; if `deferred.notify` still applicable , should work ok , or similar to your accepted Answer . Read `move.js` documentation , included `.end()` callback . Thanks – guest271314 Jul 26 '14 at 21:34
  • @guest271314 - This is the best I can find in terms of references about the future of `.progress` [here](http://stackoverflow.com/questions/23403814/how-do-promises-a-implementations-vary/23404096#23404096) and [here](http://stackoverflow.com/questions/23865481/how-to-call-q-promise-notify-within-the-promise-chain/23866364#23866364). – jfriend00 Jul 26 '14 at 22:05
  • Interesting. A fair amount of approaches available . Should be able to build `progress` , `notify` callbacks , with one of the various alternatives , if needed. Composed a modest `.done()` and `when` for native `promise` here http://stackoverflow.com/a/23587868/2801559. Thanks , again. – guest271314 Jul 26 '14 at 22:20
0

Edit, Added callback function to .end() to include deferred.notify . See comments , Move#end([fn])

Try

var deferred = new $.Deferred();
click(e); // `e` undefined ?
deferred.progress(function(msg) {
// `this` within `deferred`
// references `deferred` object ,
// try `obj.checkWin()`, `obj.nextLevel()`
  if (obj.checkWin()) {
    alert(msg);
    obj.nextLevel();
  }
});

function click(e) {
    // `e` undefined ?
    move(e)
    .set('background-color','black')
    // `.delay()` accepts `number` as argument ? 
    .delay('0.1s')
      // see comments , 
      // http://visionmedia.github.io/move.js/#example-11
    .end(function() {
      deferred.notify("you won !");
    });
};

jsfiddle http://jsfiddle.net/guest271314/4Av4Z/

guest271314
  • 1
  • 15
  • 104
  • 177
  • This won't work because you're notify the progress event before the animation has finished. – jfriend00 Jul 26 '14 at 15:59
  • @jfriend00 If possible, please indicate line within the piece at post where progress event is fired before the animation has finished ? Thanks – guest271314 Jul 26 '14 at 16:05
  • Animations in javascript are asynchronous. – jfriend00 Jul 26 '14 at 16:09
  • @jfriend00 If possible, can please indicate line within piece at post where progress event is fired before the animation has finished ? Thanks – guest271314 Jul 26 '14 at 16:12
  • Asynchronous operations such as animations finish sometime in the future (they run by timers or by native CSS transitions/animations). The only way to know when they are done is to use some sort of completion notification. – jfriend00 Jul 26 '14 at 16:17
  • If `end()` is chained to fire _after_ `delay()` , and `deferred.notify()` fires _after_ `.end()` , `deferred.progress()` does not fire until after `.delay().end()` , i.e., after `animation` has finished ? Again, at 1st comment , ( "downvote" ? ), "This won't work because you're notify the progress event before the animation has finished. – jfriend00" . Please indicate specific line at Answer applicable to comment / downvote . Thanks – guest271314 Jul 26 '14 at 16:17
  • Do you know what it means to have an asynchronous animation? It sounds like you don't. The animation finishes sometime in the future, long, long after `.end()` has been executed. Animations in javascript are NOT synchronous. The ONLY way to know when the animation is done is to use the optional callback to `.end()` like my answer shows. – jfriend00 Jul 26 '14 at 16:31
  • That looks better using the `.end()` callback to trigger the `.notify()`. – jfriend00 Jul 26 '14 at 21:34