John23
John23

Reputation: 199

get SetTimeout to finish before continuing loop

I'm trying to get a row of letters to light up one by one using Javascript/jquery. I created an array using span elements and am looping over each letter to first change its color red and then back to black again. The problem is that the $.each loop function doesn't wait for setTimeout to finish...it loops over all of them instantly making them all turn red instantly instead of one by one. Any ideas how to fix this? Here is my code:

JSFiddle: http://jsfiddle.net/john23/8chu18k9/

var array = $(".one");

var doIt = function () {
    $.each(array, function(index, value){
            array.eq(index).css('color','red');
        setTimeout(function(){
            array.eq(index).css('color','black');                                
        }, 500);
    });

};

doIt();
P {
    color:black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>
    <span class="one">H</span><span class="one">e</span><span class="one"></span><span class="one">l</span><span class="one">l</span><span class="one"></span><span class="one">o</span><span class="one"> M</span><span class="one"></span><span class="one">y </span><span class="one">N</span><span class="one"></span><span class="one">a</span>
</p>

Upvotes: 1

Views: 12612

Answers (3)

Ji_in_coding
Ji_in_coding

Reputation: 1701

In case you want the setTimeout solution. Here it is.

Html:

<p>
  <span class="one">H</span>
  <span class="one">e</span>
  <span class="one">l</span>
  <span class="one">l</span>
  <span class="one">o</span>
  <span class="one"> M</span>
  <span class="one">y </span>
  <span class="one">N</span>
  <span class="one">a</span>
</p>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>

Css:

P {
    color:black;
}

Js:

var delayBase = 10;
var baseDuration = 500; //Time at which each span stays red for

$(document).ready(function(){
  $(".one").each(function(){
    flash($(this), delayBase, baseDuration);
    delayBase+=1000;
  });
});

function flash($element, delay, flashDuration){ 
  //set red
  setTimeout(function(){
    $element.css('color', 'red');
  }, delay );
  //set black
  setTimeout(function(){
    $element.css('color', 'black');
  }, (delay+flashDuration) );
}

codepen example: http://codepen.io/anon/pen/zxzeKE

Upvotes: 1

Brennan
Brennan

Reputation: 5732

setTimeout is asynchronous. It will return control back to the calling context immediately, so this code will not work as expected. I suggest using setInterval instead, which runs the same function repeatedly, at the given interval:

var array = $('.one');
var currentIndex = 0;
var intervalId = setInterval(function(){
  array[currentIndex].css('color','black');
  currentIndex++;
  // We've reached the end of the array, stop calling this function
  if (currentIndex == array.length) clearInterval(intervalId);
}, 500);

To clarify a little: setInterval will return an ID. You can then pass that ID to the function clearInterval to stop the invocation of the function.

Upvotes: 2

bitoiu
bitoiu

Reputation: 7474

This is what you want: http://jsfiddle.net/8chu18k9/1/

var array = $(".one");
var i = 0;

var doIt = function () {

    setTimeout(loopIt, 500)       
};

var loopIt = function() {

    if(i < array.length) {
        console.log("inner loop")
          array.eq(i).css('color','red');   
        if(i > 0) {
            array.eq(i-1).css('color','');               
        }        
        i++
        setTimeout(loopIt, 500)
    }    
}


doIt();

If you don't want the letters to go back to black, delete:

 if(i > 0) {
     array.eq(i-1).css('color','');               
 }        

Upvotes: 1

Related Questions