lemonWedge
lemonWedge

Reputation: 23

jQuery - Pausing for loop with nested setTimeout

I am trying to use Timeout to pause a for loop which is going to animate some elements. I want to get some buttons to expand one after the other.

At the moment I have two problems. The first is that eq.(j) seems to have an element index 1 greater than it seems like it should. The other is that it skips to the last animation.

 for (j = 0; j<=numberOfButtons; j++){
    setTimeout(function() { 
         $buttons.eq(j).animate({
            height: buttonBig,
            width: buttonBig
        },150, 'linear');
    }, 3000 * (j + 1)); 
 }

This is my first time using stackoverflow, so let me know if I'm posting this question correctly.

Thanks for your help in advance.

Upvotes: 2

Views: 967

Answers (1)

Sampath Liyanage
Sampath Liyanage

Reputation: 4896

Use a temporary scope. You are calling an asynchronous function setTimeout...

In your code you are scheduling events with settimeOut() functions. When your code runs, one iteration doesn't wait after calling settimeOut() function. It just keep scheduling all the setTimeout events for j=0 to j<=numberOfButtons. Then js keep executing the rest of the code below the loop until the timeout events occur...

when the timeout events occur, all the timeout events are scheduled and the value of j is equal to numberoOfButtons...

Now another concept used in javascript comes to action. The concept is called "scope". A scope of a function can be defined as the variables that function can access (not a very accurate definition). In javascript, a function's scope includes variables of it's parent function too (not only parents, variables of grandparent and so on..)...

In your code, when timeout events occurs, the callback functions are called. When the callbacks are executed, the value of j that each callback refers is not what you are thinking it is. The value of j is equal to numberOfButtons in the parent function. Therefore all the callbacks refers that value when executing callbacks which leads to the unexpected behaviour.

What I did was I added another function with input parameter as j, and called it. This function is called in every iteration of the loop, setting j to a new value. Now when the callbacks are executed there parent function is not the function that has the for loop. The parent function is the anonymous function I added. The j values of that anonymous functions are local to each function and different. Because of that, when callbacks are executed, they refer the j value which they are supposed to refer. That's why it gives the expected behaviour.

for (j = 0; j<=numberOfButtons; j++){
    (function(j){
       setTimeout(function() { 
         $buttons.eq(j).animate({
            height: buttonBig,
            width: buttonBig
        },150, 'linear');
      }, 3000 * (j + 1)); 
   })(j); 
 }

Upvotes: 5

Related Questions