Reputation: 178
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);
}
});
}
Upvotes: 8
Views: 3380
Reputation: 173532
I would reverse the workings:
For each string:
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);
}
Upvotes: 3
Reputation: 4297
How about simplifying? Use two variables to iterate the entire contents of a slightly modified data structure in a single loop. Like this. http://jsfiddle.net/cXykd/
var strings =
[
{ "id":"listitem1", "text": "write the first item" },
{ "id":"listitem2", "text": "write the second item" },
{ "id":"listitem3", "text": "write the third item" },
{ "id":"listitem4", "text": "write the fourth item" },
{ "id":"listitem5", "text": "write the fifth item" },
]
var stringsIndex = 0;
var textIndex = 0;
AddString();
function AddString(){
if (stringsIndex < strings.length){
if (textIndex >= strings[stringsIndex].text.length)
{
stringsIndex++;
if (stringsIndex == strings.length)
{
return;
}
textIndex = 0;
}
$("#" + strings[stringsIndex].id).append(strings[stringsIndex].text[textIndex]);
textIndex++;
var delay = 10 + Math.floor(Math.random()*11)*6;
setTimeout(AddString, delay);
}
}
Upvotes: 1
Reputation: 10374
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');
});
Upvotes: 4