Reputation: 3496
What I want is this (news ticker type functionality):
That's the goal, but setTimeout is not running as I thought it would. Only the LAST iteration ("Post Four") is showing. And that ("Post Four") is showing four times in a row.
<body>
<ul id="post_list">
<li>Post One</li>
<li>Post Two</li>
<li>Post Three</li>
<li>Post Four</li>
</ul>
<script type="text/javascript">
var ul = document.getElementById('post_list');
var li = ul.getElementsByTagName('li');
for(var x=0; x < li.length; x++){
var li_text = li[x].childNodes[0].nodeValue;
setTimeout(function(){showText(li_text)}, 1000);
}
function showText(text) {
console.log(text);
}
</script>
</body>
Upvotes: 1
Views: 534
Reputation: 10177
As Greg mentioned the problem is with the closure only evaluating once. Nobody posted a solution for this so here is one. This uses adding a function that generates the callback function each time:
Add:
function getShowTextCallback(text) {
return function(){showText(text)}
}
Then use it in loop like this:
for(var x=0; x < li.length; x++){
var li_text = li[x].childNodes[0].nodeValue;
setTimeout(getShowTextCallback(li_text), 1000);
}
Upvotes: 2
Reputation: 17666
How about we just move some of the code around a bit... take out the closure issue...
var ul = document.getElementById('post_list');
var li = ul.getElementsByTagName('li');
for (var x = 0, xl = li.length; x < xl; x++) {
var li_text = li[x].innerText || li[x].textContent; // does IE support textContent??
showText(li_text, x * 1000);
}
function showText(text, delay) {
setTimeout(function() {
console.log(text);
}, delay);
}
I assume the delay you want to be sequential (hence the loop). Because setTimeout is not blocking you will need to have a callback on the function to invoke the next setTimeout or you will need to specifically increment each function call with a new delay.
Upvotes: 0
Reputation: 4083
The reason this is happening is because of closures. The for loop block has closures around it, so when you reference 'li_text' it was always equal the last value that li_text was set to. The for loop does not create a separate closure for each iteration through the loop.
Upvotes: 4
Reputation: 35274
Change this:
for(var x=0; x < li.length; x++){
var li_text = li[x].childNodes[0].nodeValue;
setTimeout(function(){showText(li_text)}, 1000);
}
To:
for(var x=0; x < li.length; x++) (function() {
var li_text = li[x].childNodes[0].nodeValue;
setTimeout(function(){showText(li_text)}, x * 1000);
})()
Upvotes: 0