David
David

Reputation: 4873

Javascript wait for one animation to finish before the next one begins

I have a Javascript function (Not jQuery) that animates a box opening or closing. The problem is that I close the box, run some code that changes the content, and then reopen it.

Now the "problem" is that the rest of the code is too fast, and so it never even manages to close, let alone reopen. I could make the animation not be allowed to run again internally unless the last one was finished, but this would limit it if I say, were to want to run it twice on two different objects.

So what's the best method to prevent this? My thought was possibly a timeout that says to wait before running the animation, but that seems hacky, an I wasn't sure if there was a better solution?

Thanks.

function animate(boxID, step, limit, speed){
    // Add timeout property to animate function/object if it doesn't exist already
    if(animate.timeout == undefined) animate.timeout = 0;

    // Clear the current timeout
    clearTimeout(animate.timeout);

    // Initialize box and current box height
    var box = document.getElementById(boxID);
    var h   = box.clientHeight;

    // Check if we want the step needs to be changed to pos/neg based on which direction is wanted to be going
    if(h < limit && step < 0 || // Positive
       h > limit && step > 0){  // Negative
        step *= -1;
    }


    // If the step is positive, then we need to be below the limit, or if negative, then greater than the limit
    if((step > 0 && h <= limit - step) || (step < 0 && h >= limit - step)){
        // Set new height
        box.style.height = h + step + "px";

        // Start new timeout
        animate.timeout = setTimeout(function(){ animate(boxID, step, limit, speed, 1); }, speed);
    }
    else{
        box.style.height = limit + "px"; // Set to the exact height
    }
}

Upvotes: 0

Views: 1965

Answers (1)

zord
zord

Reputation: 4783

You could achieve this with a callback. Your animate function gets a plus parameter, a function to call when the animation is ready:

function animate(boxID, step, limit, speed, onReady){

When the animation is done, you call it:

else{
    box.style.height = limit + "px"; // Set to the exact height
    if (onReady) { onReady(); }
}

You also want to forward the callback to the timeout call:

setTimeout(function(){ animate(boxID, step, limit, speed, 1, onReady); }, speed);

So, you can call the function for multiple boxes like this:

animate(box1_id, close_step, close_limit, close_speed, function () {
    // now box1 is closed, put something in. then:
    animate(box1_id, open_step, open_limit, open_speed, null);
});
// then the same for box2, etc…

This way box1 and box2 will close simultaneously, and only reopen after the thing have been put inside.

Also, you can't store the timer on the function, because now it's running on multiple boxes. So you may store it on the boxes, or a separate place instead. For example create an object outside of the function and put all the boxes' timers in that:

var timeouts = {};
timeouts[box1_id] = setTimeout(…);

Upvotes: 1

Related Questions