Trevor
Trevor

Reputation: 149

How to wait until a loop of jquery effects are finished before executing function

Edit: The accepted answer here: How to get jQuery to wait until an effect is finished? does not solve my problem because the callback function is executed before the jquery ui effects have been completed. Also there is another answer on this thread which refers to promise() but this is only part of the answer and is missing much information.

I'm trying to wait until a loop of jquery effects has fully completed animations until executing a callback function.

However it seems that the callback function is executed immediately after the last jquery effect is started, but does not wait for the animations to finish.

I'm wondering how I can wait for the elements to be hidden using jquery drop effect for all elements in the loop, and only after the elements have been hidden completely the callback function is run.

<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
</head>
<body>
    <button id="execute-button">Execute</button>
    <div id="messagebox"></div>
    <div id="1" style="background-color:blue;display:none;height:33%;width:100%;"></div>
    <div id="2" style="background-color:green;display:none;height:33%;width:100%;"></div>
    <div id="3" style="background-color:red;display:none;height:34%;width:100%;"></div>
    <div id="4" style="background-color:brown;height:33%;width:100%;"></div>
    <div id="5" style="background-color:black;height:33%;width:100%;"></div>
    <div id="6" style="background-color:gray;height:34%;width:100%;"></div>
    <script>
        $(document).ready(function(){

            function hideElements(callback){
                //hide elements
                var hideDivs = ["#4","#5","#6"];
                for(i = 0; i < hideDivs.length; i++){
                    //alert("hiding...");
                    $(""+hideDivs[i]).hide("drop",{direction:"left"},5000);
                    //alert(divs[i]);
                }
                callback();
            };

            function showElements(){
                //show elements
                var showDivs = ["#1","#2","#3"];
                //alert(JSON.stringify(divs));
                for(i = 0; i < showDivs.length; i++){
                    //alert("showing...");
                    $(""+showDivs[i]).show("drop",{direction:"right"},1000);
                    //alert(divs[i]);
                }
            }


            hideElements(showElements());

        });


        $(document).on("click","#execute-button", function(){
            //$("#messagebox").html("test");
            $("#1").show("#1");
        });
    </script>
</body>
</html>

Upvotes: 2

Views: 1992

Answers (1)

jfriend00
jfriend00

Reputation: 707298

In jQuery, if you use .promise() on a jQuery collection, it will return a promise that is resolved when all the elements in the collection have finished their animation. So, you should be able to just fire the .hide() animation on each element, then do .promise() on the collection and when that promise resolves, you can then do the other animation.

Here's a working snippet example:

// returns a promise that resolves when all animations started here are done
function showHide() {
    var items = $("#4, #5, #6");
    return items.slideUp(2000).promise().then(function() {
        // this runs when all animations in the items collection are done
        return items.slideDown(2000).promise();
    });
}

$("#go").click(function() {
    showHide().then(function() {
        console.log("animation done");
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


<div>
<button id="go">Run</button>
</div>

<div style="height: 300px;">
    <div id="4" style="background-color:brown;height:33%;width:100%;"></div>
    <div id="5" style="background-color:black;height:33%;width:100%;"></div>
    <div id="6" style="background-color:gray;height:34%;width:100%;"></div>
</div>


Of course if all your first group of animations have the same timing, you can just use jQuery animation chaining (where animations for a given object go into a queue and a subsequent animation waits for the prior one to be done before starting):

// returns a promise that resolves when all animations started here are done
function showHide() {
    return $("#4, #5, #6").slideUp(2000).slideDown(2000).promise();
}

Upvotes: 5

Related Questions