1

I have two functions, tick and tock. They cause 4 numbers to spin one direction then the other. Each number can ease at a different rate.

I can call both functions but I cannot get the second (tock) to wait until all the numbers have finished moving in the first (tick).

I have looked at other similar questions where a callback is used but I cannot seem to implement this with my example. I either end up with the second function proceeding before the first is finished or as is the case with the code below, only the first function is used.

Thanks

$(document).ready(function(){
var complete = 0;

tick('', function(){tock();});

function tick(a){

    $('#col1 img')
        .delay('1000')
        .animate({bottom:'-=80px'},5000,'easeInOutSine');
        complete++;

    $('#col2 img')
        .delay('1000')
        .animate({bottom:'+=720px'},1000,'easeInOutSine');
        complete++;


    $('#col3 img')
        .delay('1000')
        .animate({bottom:'+=560px'},500,'easeInOutSine');
        complete++;


    $('#col4 img')
        .delay('1000')
        .animate({bottom:'-=240px'},2000,'easeInOutSine');
        complete++;

}

function tock(){
    $('#col1 img')
        .delay('1000')
        .animate({bottom:'+=80px'},2000,'easeInOutSine');

    $('#col2 img')
        .delay('1000')
        .animate({bottom:'-=720px'},2000,'easeInOutSine');

    $('#col3 img')
        .delay('1000')
        .animate({bottom:'-=560px'},2000,'easeInOutSine');

    $('#col4 img')
        .delay('1000')
        .animate({bottom:'+=240px'},2000,'easeInOutSine');
}
});
1
  • I'm trying to figure out how to help but what you're asking is pretty unclear. So tock() runs every four times tick() runs? Commented Jun 13, 2013 at 15:40

1 Answer 1

4

You have to wait until all the animations are done and then call the other function. All jQuery objects implement the promise interface [docs] and they get resolved when any animation finished. Together with $.when [docs], you can easily achieve what you want:

function tick(callback){

    var p1 = $('#col1 img')
        .delay('1000')
        .animate({bottom:'-=80px'},5000,'easeInOutSine')
        .promise();

    var p2 = $('#col2 img')
        .delay('1000')
        .animate({bottom:'+=720px'},1000,'easeInOutSine')
        .promise();


    var p3 = $('#col3 img')
        .delay('1000')
        .animate({bottom:'+=560px'},500,'easeInOutSine')
        .promise();


    var p4 = $('#col4 img')
        .delay('1000')
        .animate({bottom:'-=240px'},2000,'easeInOutSine')
        .promise();

    // $.when returns a new promise which is resolved once each passed promise 
    // is successfully resolved
    $.when(p1, p2, p3, p4).done(callback);
}

function tock(){
    // same as the original code
}

tick(tock);

More information about promises / deferreds: http://api.jquery.com/category/deferred-object/.


Since so much code repetition makes me anxious, here is a refactored version of the tick function:

function tick(callback) {
    var data = [
        {props: {bottom: '-=80px'}, duration: 5000},
        {props: {bottom: '+=720px'}, duration: 1000},
        {props: {bottom: '+=560px'}, duration: 500},
        {props: {bottom: '-=240px'}, duration: 2000}
    ];
    var promises = [];

    // assuming the elements are in the correct document order
    $('#col1, #col2, #col3, #col4').find('img').each(function(i) {
        var d = data[i];
        promises.push(
            $(this).delay(1000).animate(d.props, d.duration, 'easeInOutSine').promise()
        );
    });

    $.when.apply($, promises).done(callback);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Perfect. And thanks very much for tidying up the code. Much appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.