2

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>
Community
  • 1
  • 1
Trevor
  • 139
  • 1
  • 10
  • Need to use callbacks that respond when the hide event finishes http://api.jquery.com/hide/ – garryp Nov 08 '16 at 22:22
  • @jfriend00 The supplied duplicate shows how to wait until a single effect is finished, not multiple, which is what this question is asking, if I'm not mistaken. – Heretic Monkey Nov 08 '16 at 22:26
  • @MikeMcCaughan - The answer in that dup with 143 upvotes works just fine for multiple objects. `$(selector).promise().done()` captures all animations running in all the objects matched by that selector. – jfriend00 Nov 08 '16 at 22:32
  • @jfriend00 the answer you're referring to is very incomplete. I just figured out the complete solution and it requires using resolve() method, $.when.apply method as well as passing an array of deferreds to apply method... I would post my final code for answer but I can't since it's marked as duplicate – Trevor Nov 09 '16 at 19:56
  • @user1504519 - I don't know why you're doing what you're doing because it sounds way more complicated than necessary. You were apparently not using my prior suggestion to use `$(selector).promise().done()`. I reopened the question and offered you an answer. – jfriend00 Nov 09 '16 at 22:48

1 Answers1

5

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();
}
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • You can also do `items.slideUp(2000).slideDown(2000).promise().then(function() { … })` as animations chain anyway – Bergi Nov 09 '16 at 23:34
  • @Bergi - Yeah, but the more general part of this question is how to know when a group of animations are done (all of which may not have the same duration in the general case) so you can then start a second group of animations. So I thought this taught more useful stuff than just chaining animations. I will add some info about animation chaining to my answer for completeness. – jfriend00 Nov 09 '16 at 23:45