user1607991 user1607991 - 5 months ago 20
Javascript Question

Complete function not forcing jquery to wait for end of animation

I am trying to use a counter in my complete function to make sure the animation of margin-top is completed before moving on. Right now, I have the counter in my MakeList(), and in my Spin() function, I console.log the counter and it doesn't recognize the counter++ because it fires before the animation finishes. Nobody I ask can figure out why.

** Note: I can't use timeOut's because the time is set to random (supposed to look like a slot machine ** Also, I can't find what this test platform is saying is an error, but the code runs on my machine. really the script-2.js is all i need to show to get point across though :)



// ********************************************************
// SLOT MACHINE ICONS. Each array has 3 icons for each slot
// ********************************************************

var array1 = [
'<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
'<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
'<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
var array2 = [
'<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
'<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
'<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
var array3 = [
'<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
'<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
'<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]


// Generates random # between 0 and 2. Used for choosing winner and creating random slots
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

// Generates winning array item between coffee, tea and espresso
function win(whatArray){
var arrayItem = getRandomInt(0,2);
var winItem = whatArray[arrayItem];
return winItem;
}

// Populates each slot with random icons to spin through
var makeList = function(whatArray, whatSlot){
var slotArray = [];

for(i=0; i < 100; i++){

var randNum = getRandomInt(0,2); // Generate random number
var findItem = whatArray[randNum]; // Use random number to find associated array item
var slot = whatSlot; // Set which slot to append array item to (first, second or third)
$('#' + slot).append('<div>'+findItem+'</div>'); // Append icon to HTML
}

var winItem = win(whatArray); // Generate winning icon for slot
console.log("winner " + winItem);
$('#' + slot).append('<div>'+winItem+'</div>'); // Append winning icon to end of list
}





// Spin the slot and win some caffeine!
function Spin(){

window.counter = 0;

// Generate lists for each slot
makeList(array1, 'slot-1');
makeList(array2, 'slot-2');
makeList(array3, 'slot-3');

MoveSlots($('#slot1-wrapper'), 2500);
MoveSlots($('#slot2-wrapper'), 5200);
MoveSlots($('#slot3-wrapper'), 500);

//var running = true;
// console.log(running);

var slot1attr = $('#slot1-wrapper div').children().last().attr('data-id');
var slot2attr = $('#slot2-wrapper div').children().last().attr('data-id');
var slot3attr = $('#slot3-wrapper div').children().last().attr('data-id');

console.log('counter = ' + counter);

if(counter > 0){
if(slot1attr == slot2attr && slot1attr == slot3attr ){

console.log("WIN");
} else {
console.log("LOSE");
}
}


function MoveSlots(el, speed){

var time = speed;
time += Math.round(Math.random()*10000);
el.stop(true,true);

var marginTop = -(100 * 150 ); //change 100 to height placeholder

var running = true;

el.animate({
'margin-top':'+='+marginTop+'px'
}, {
'duration' : time,
'easing' : 'easeInOutQuint',
complete: function(){

console.log('yolo');
//$(this).on('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function(){
counter++;
console.log(counter);
//})

}
});

} // end MoveSlots
} // end Spin

body{
/*background-color:white;*/
padding:50px;
margin:50px;
background: #505f77 !important;
}

#slotWrapper {
width:410px;
height:150px;
margin:50px auto;
overflow: hidden;
position:relative;
border:1px solid #f00;

}
#slot1-wrapper, #slot2-wrapper, #slot3-wrapper {
margin-top:0;
position: relative;
}
.slot {
width:120px;
height:150px;
margin-right:25px;
text-align:center;
float:left;
position: absolute;
}
#slot-3 {
margin-right:0;
}
#slot-1 {
top:0;
left:0;
}
#slot-2 {
top:0;
left:145px;
}
#slot-3 {
top:0;
left:290px;
}
.slot div {
width:120px;
height:150px;
}

.slot div img {
width:100%;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>

</head>
<body>

<link rel="stylesheet" type="text/css" href="css/style.css" />
<!-- <link rel="stylesheet" type="text/css" href="css/default.css" />
<link rel="stylesheet" type="text/css" href="css/component.css" /> -->
<div style="text-align:center">
<input type="button" value="spin!" onClick="Spin();" style="margin-top:4px;">
</div>

<div id="slotWrapper">

<div id="slot1-wrapper">
<div id="slot-1" class="slot"></div>
</div>
<div id="slot2-wrapper">
<div id="slot-2" class="slot"></div>
</div>
<div id="slot3-wrapper">
<div id="slot-3" class="slot"></div>
</div>

</div>


</body>
</html>




Answer

The problem is complete is executed asynchronously, ie the counter condition is executed is before the animations are completed.

You can use the animation promise to solve it

//  ********************************************************
//  SLOT MACHINE ICONS. Each array has 3 icons for each slot 
//  ********************************************************

var array1 = [
  '<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
  '<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
  '<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
var array2 = [
  '<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
  '<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
  '<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
var array3 = [
  '<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
  '<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
  '<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]


//  Generates random # between 0 and 2. Used for choosing winner and creating random slots
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

//  Generates winning array item between coffee, tea and espresso
function win(whatArray) {
  var arrayItem = getRandomInt(0, 2);
  var winItem = whatArray[arrayItem];
  return winItem;
}

//  Populates each slot with random icons to spin through
var makeList = function(whatArray, whatSlot) {
  var slotArray = [];

  for (i = 0; i < 100; i++) {

    var randNum = getRandomInt(0, 2); // Generate random number
    var findItem = whatArray[randNum]; // Use random number to find associated array item
    var slot = whatSlot; // Set which slot to append array item to (first, second or third)
    $('#' + slot).append('<div>' + findItem + '</div>'); // Append icon to HTML 
  }

  var winItem = win(whatArray); // Generate winning icon for slot
  console.log("winner " + winItem);
  $('#' + slot).append('<div>' + winItem + '</div>'); // Append winning icon to end of list
}





// Spin the slot and win some caffeine!
function Spin() {

    var counter = 0;

    //  Generate lists for each slot
    makeList(array1, 'slot-1');
    makeList(array2, 'slot-2');
    makeList(array3, 'slot-3');

    var p1 = MoveSlots($('#slot1-wrapper'), 2500);
    var p2 = MoveSlots($('#slot2-wrapper'), 5200);
    var p3 = MoveSlots($('#slot3-wrapper'), 500);

    $.when(p1, p2, p3).then(function() {
      //var running = true;
      // console.log(running);

      var slot1attr = $('#slot1-wrapper div').children().last().attr('data-id');
      var slot2attr = $('#slot2-wrapper div').children().last().attr('data-id');
      var slot3attr = $('#slot3-wrapper div').children().last().attr('data-id');

      console.log('counter = ' + counter);

      if (counter > 0) {
        if (slot1attr == slot2attr && slot1attr == slot3attr) {

          console.log("WIN");
        } else {
          console.log("LOSE");
        }
      }

    });

    function MoveSlots(el, speed) {

        var time = speed;
        time += Math.round(Math.random() * 10000);
        el.stop(true, true);

        var marginTop = -(100 * 150); //change 100 to height placeholder

        var running = true;

        el.animate({
          'margin-top': '+=' + marginTop + 'px'
        }, {
          'duration': time,
          'easing': 'easeInOutQuint',
          complete: function() {
            console.log('yolo');
            counter++;
            console.log(counter);
          }
        });

        return el.promise();
      } // end MoveSlots
  } // end Spin
body {
  /*background-color:white;*/
  padding: 50px;
  margin: 50px;
  background: #505f77 !important;
}
#slotWrapper {
  width: 410px;
  height: 150px;
  margin: 50px auto;
  overflow: hidden;
  position: relative;
  border: 1px solid #f00;
}
#slot1-wrapper,
#slot2-wrapper,
#slot3-wrapper {
  margin-top: 0;
  position: relative;
}
.slot {
  width: 120px;
  height: 150px;
  margin-right: 25px;
  text-align: center;
  float: left;
  position: absolute;
}
#slot-3 {
  margin-right: 0;
}
#slot-1 {
  top: 0;
  left: 0;
}
#slot-2 {
  top: 0;
  left: 145px;
}
#slot-3 {
  top: 0;
  left: 290px;
}
.slot div {
  width: 120px;
  height: 150px;
}
.slot div img {
  width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.js"></script>
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/redmond/jquery-ui.css" rel="stylesheet" />
<div style="text-align:center">
  <input type="button" value="spin!" onClick="Spin();" style="margin-top:4px;">
</div>

<div id="slotWrapper">

  <div id="slot1-wrapper">
    <div id="slot-1" class="slot"></div>
  </div>
  <div id="slot2-wrapper">
    <div id="slot-2" class="slot"></div>
  </div>
  <div id="slot3-wrapper">
    <div id="slot-3" class="slot"></div>
  </div>

</div>