Cristian
Cristian

Reputation: 495

javascript wait til function is finished

I have a javascript function that goes like this:

$(document).keydown(function(e) {
    switch(e.which) {
        case 38:
            moveUp();
            break;
        case 40:
            moveDown();
            break;
    }
});
function moveDown() {
    $('element').animate({top: "100%"}, {duration: 1000 });
}
function moveUp() {
    $('element').animate({top: "-100%"}, {duration: 1000 });
}        

My question is how would I create a delay in the keydown function that tells it that it has to wait until the function moveUp()/movedown() is finished before calling the function again without creating a queue?

Thank you for all the advise, by the way, I cant use setTimeout because it would cause a delay on every initial function.

Upvotes: 2

Views: 395

Answers (4)

gaetanoM
gaetanoM

Reputation: 42044

I may suggest you to set a data attribute.

The animate has a complete callback. So before starting the animation you may set the attribute to false and when the animation is completed you may reset to true this attribute.

This attribute can be tested in the keydown event to decide if it's right to continue.

$(function () {
  // set the data attribute to true
  $(document).data('isAnimateCompleted', true);

  $(document).keydown(function(e) {
    // if false return
    if ($(document).data('isAnimateCompleted') == false) {
      return;
    }
    switch(e.which) {
      case 38:
        moveUp();
        break;
      case 40:
        moveDown();
        break;
    }
  });
  function moveDown() {
    // before starting set to false
    $(document).data('isAnimateCompleted', false);
    $('#element').animate({top: "100px"}, 1000, function() {
      // when completed set to true
      $(document).data('isAnimateCompleted', true);
    });
  }
  
  function moveUp() {
    $(document).data('isAnimateCompleted', false);
    $('#element').animate({top: "0px"}, 1000, function() {
      $(document).data('isAnimateCompleted', true);
    });
  }
});
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>

<div id="element" style="position: fixed;top: auto;">This is an element</div>

Another possibility is to use the jQuery animated selector to test if the animation is in progress avoiding at all global variables.

Upvotes: 0

krozero
krozero

Reputation: 6433

Here's easy solution.

var flag = true;
$(document).keydown(function(e) {
  if(flag == true){
  	switch (e.which) {
      case 38:
        moveUp();
        break;
      case 40:
        moveDown();
        break;
    }
  }
  
});



function moveDown() {
  $('#elem').animate({
    top: "100px"
  }, {
    duration: 1000,
    start: function(){ flag=false; },
    complete: function(){flag=true; }
  });
}

function moveUp() {
	
  $('#elem').animate({
    top: "0px"
  }, {
    duration: 1000,
   	start: function(){ flag=false; },
    complete: function(){flag=true; }
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="background: green; width: 100px; height: 100px; position:absolute;" id="elem">

</div>

Upvotes: 3

user94559
user94559

Reputation: 60143

Assuming you want keypresses to have no effect at all while an animation is in progress, this should help. When the animation is about to start, I set a variable called inProgress to true. I set it back to false in the completed handler for the animation. In the keydown handler, I check that flag, and if an animation is in progress, I ignore the key.

var position = 50;
var inProgress = false;

function move() {
  inProgress = true;
  $('#box').animate({ top: position + 'px', duration: 1000 }, function () {
    inProgress = false;
  });
}

$(document).keydown(function(e) {
  if (inProgress) {
    return;
  }
  switch(e.which) {
    case 38:
      e.preventDefault();
      position -= 10;
      move();
      break;
    case 40:
      e.preventDefault();
      position += 10;
      move();
      break;
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box" style="position:absolute;top:50px;background-color:blue;width:50px;height:50px"></div>

Upvotes: 3

Shlomi Haver
Shlomi Haver

Reputation: 974

This should help you, I used the complete function of the animate to execute the next action as soon as it's finish animating.

var isAnimating = false;
var callAfterFinish = undifined;
$(document).keydown(function(e) {
    switch(e.which) {
        case 38:
            moveUp();
            break;
        case 40:
            moveDown();
            break;
    }
});
function moveDown() {
    if(!isAnimating){
        $('element').animate({top: "100%"}, {duration: 1000 },function(){
            if(!callAfterFinish) {
                callAfterFinish();
                callAfterFinish = undifined;
            }
            isAnimating = false;
        });
        isAnimating = true;
    } else if(!callAfterFinish) {
        callAfterFinish = moveDown;
    }
}
function moveUp() {
    if(!isAnimating){
        $('element').animate({top: "-100%"}, {duration: 1000 },function(){
            if(!callAfterFinish) {
                callAfterFinish();
                callAfterFinish = undifined;
            }
            isAnimating = false;
        });
        isAnimating = true;
    } else if(!callAfterFinish) {
        callAfterFinish = moveUp;
    }
}        

Upvotes: 3

Related Questions