3

Details

I have a function with animations inside, when clicking the button it will .append a div to the body. The div will then animate its position moving down a little bit. When another is added all of the divs will move down too so they will not overlap.

Now we run into the problem! When spamming the button to create the divs they will overlap.

How can we stop this from happening?

Notes:

  • So only when the last function has completed all animations the next call can start
  • Needs to remember and run the function how many time you clicked the button
  • The function in my plugin has options that will need to be remembered (e.g the color of the background for the popup).

What I Have Tried

The way I see it is that I would like to create a queue for how many times you click the button and release the next in line after x amount of time has past (enough to finish all the animations). Problem is that I cannot find a way to do this in jQuery.

  • I have looked into using .queue in jQuery but fail to see a way this can help with this matter.
  • I have put a setTimeout onto the function but this causes a delay on the click

I feel like this is something very simple but I cannot find a solution after a few hours of messing around with it myself.

The Demo

I have created a demo for this question, my real version is a plugin so therefor is its own function. This is just a very basic version.

$("button").click(function() {
  $("body").append("<div></div>");

  $($("div").get().reverse()).each(function(index) {
    $(this).animate({
      top: "+=120px"
    }, {
      duration: 600,
      queue: false
    });

    if (index >= 2) {
      // Fade out and then remove the item
      $(this).fadeOut("fast", function() {
        $(this).remove();
      });
    }
  });
});
div {
  width: 400px;
  height: 50px;
  background: rgba(0, 0, 0, .4);
  position: absolute;
  top: 0;
  right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click</button>

JSFiddle Demo

3
  • Do you want ot add animations in a queue or just not to allow new animation before previos is done? Commented Sep 4, 2015 at 13:30
  • @LazarevAlexandr I want to remember the function has been called and only start the next one after the function running before has finished (along with all of its animations). Commented Sep 4, 2015 at 13:40
  • so actually it is a queue :) Commented Sep 4, 2015 at 14:32

2 Answers 2

3

Try this solution.... prevent animation until animate callback

animated = false;
$("button").click(function() {
  if(animated)
     return false;
  else
    animated = true;
  $("body").append("<div></div>");

  $($("div").get().reverse()).each(function(index) {
    $(this).animate({
      top: "+=120px",
      duration: 600,
      queue: false
    },function(){ animated = false; });

    if (index >= 2) {
      // Fade out and then remove the item
      $(this).fadeOut("fast", function() {
        $(this).remove();
        
      });
    }
  });
});
div {
  width: 400px;
  height: 50px;
  background: rgba(0, 0, 0, .4);
  position: absolute;
  top: 0;
  right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click</button>

This could be a starting point for manage an animation queue.

Look at this fiddle

Sign up to request clarification or add additional context in comments.

2 Comments

Its closer but this is just not counting the clicks you have done. I need to remember you clicked the button x amount of times and run the function that amount of times in order.
In my plugin the function has options with it so I would need to remember that too.
1

Adding animations to queue:

var freeToAnimate = true;
var animationQueue = [];
var i = 0;
$("button").click(function () {   
    var queueLength = animationQueue.length;    
    animationQueue.push(i);
    i++;  
    if(queueLength == 0){        
        animateDivs(i-1);  
    } else {   
        return false;                  
    }
});

function animateDivs(animationIndex) {     
      if(freeToAnimate == true) {
          freeToAnimate = false;
          var divsAmount = $("div").length;
          $("body").append("<div></div>");   
          $($("div").get().reverse()).each(function(index, el) {          
              if(index >= 2) {
                  // Fade out and then remove the item
                  $(this).fadeOut( "fast", function() {
                      $(this).remove();       
                  });
              }       

              $(this).animate({
                  top: "+=120px"               
              }, 1200, function() {
                  var indx = animationQueue.indexOf(animationIndex);
                  animationQueue.splice(indx, 1);               
                  if(index == divsAmount-1 || divsAmount == 0) {                    
                      freeToAnimate = true;  
                      if(animationQueue.length != 0) {
                          animateDivs(animationIndex+1);
                      }                
                  }                 
              });         
         });       
      }          
}      

https://jsfiddle.net/4zwmm20e/12/

Comments

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.