Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery .each waiting for function to finish before continuing through loop

I'm essentially trying to loop through a collection of LI tags and insert some text to simulate the look of someone writing a list of things to do. It works, but it writes each of the list items simultaneously instead of waiting. Is there an easy way to achieve this? I have a JS fiddle setup here: http://jsfiddle.net/fZpzT/ but the code looks like this. Thanks.

function addListItems() {
var str = {
    listitem1:'personal background check',
    listitem2:'look into my sketchy neighbor',
    listitem3:'look up my driving record',
    listitem4:'pick up milk',
    listitem5:'wash the car'
}

$('.list-container li').each(function(){
    var z = $(this).attr('id');
    var str2 = str[z];
    var delay = 0;
    for (var i = 0; i <= str2.length; i++) {
        (function(str2){
            delay += 100 + Math.floor(Math.random()*11)*6;
            setTimeout(function(){
                appendStr(str2);       
            },delay);
        })(str2[i])
    }
    function appendStr(str2) {
      $('#'+ z).append(str2);
    }
});
}
like image 805
Brian Avatar asked Feb 13 '13 01:02

Brian


2 Answers

Make the delay cumulative: Demo on jsFiddle

var str = {
    listitem1: 'write the first item',
    listitem2: 'write the second item',
    listitem3: 'write the third item',
    listitem4: 'write the fourth item',
    listitem5: 'write the fifth item'
}, cumulativeDelay = 0;

$('.list-container li').each(function () {
    var z = $(this).attr('id');
    var str2 = str[z];
    var delay = cumulativeDelay;
    for (var i = 0; i <= str2.length; i++) {
        (function (str2) {
            delay += 100 + Math.floor(Math.random() * 11) * 6;
            setTimeout(function () {
                appendStr(str2);
            }, delay);
        })(str2[i])
    }
    cumulativeDelay = delay;
    function appendStr(str2) {
        $('#' + z).append(str2);
    }
    $(this).css('color', 'red');
});
like image 82
Hari Pachuveetil Avatar answered Nov 15 '22 22:11

Hari Pachuveetil


I would reverse the workings:

  1. You start with the strings you want to write,
  2. For each string:

    1. Find the corresponding list item (by id)
    2. Write the whole string in typewriter style
    3. Invoke the next iteration when done.

      var strings = [
        'personal background check',
        'look into my sketchy neighbor',
        'look up my driving record',
        'pick up milk',
        'wash the car'
      ];
      
      function iterate(strings, idx)
      {
        if (idx >= strings.length) { return; }
      
        var id = 'listitem' + (idx + 1),
        el = document.getElementById(id);
      
        typewriter(el, strings[idx], 0, function() {
          iterate(strings, idx + 1);
        });
      }
      
      function typewriter(el, str, idx, cb)
      {
        if (idx >= str.length) {
          return cb();
        }
      
        setTimeout(function() {
          el.innerText = str.substr(0, idx + 1);
          typewriter(el, str, idx + 1, cb);
        }, 100 + Math.floor(Math.random() * 11) * 6);
      }
      

Demo

like image 41
Ja͢ck Avatar answered Nov 15 '22 21:11

Ja͢ck