I'm trying to pass an index of element and slideUp each list item content with delay
here is my code
for(var i = 1; i <= $("#colContainer li").length ; i++) {
var el = $("#colContainer li:nth-child(" + i + ") .colContent");
var delay = function() {
slide(el);
};
setTimeout(delay, 10);
function slide(el){
el.slideUp();
};
};
but every time just the last one slides up
what I expect is they slideUp from index 1 to the end with delay
I also tried this
index = $(this).parent("li").index();
for(var i = 1; i <= $("#colContainer li").length ; i++) {
(function(i) {
var el = $("#colContainer li:nth-child(" + i + ") .colContent");
var delay = function() {
slide(el);
};
setTimeout(delay, 10);
function slide(el){
el.slideUp();
};
})(i);
};
but they all slide at once, i want index 1 slide, after that index 2 and ...
IS THERE ANY WAY WITH FOR LOOP ??
This is because var el is scoped to the function block, not the loop block.
Try something like this:
for( var i=1; ......) { (function(i) {
var el = ...
// rest of your code, unchanged
})(i); }
You need a closure to scope the value of el for each iteration of the loop.
for(var i = 1; i <= $("#colContainer li").length ; i++) {
var el = $("#colContainer li:nth-child(" + i + ") .colContent");
(function(el) {
setTimeout(function(){
el.slideUp();
},10);
})(el);
}
However this will still cause them to all animate at the same time which if that is the desired result, you could just do it all in one step with jQuery.
If you want them to animate one at a time you can do this:
for(var i = 1; i <= $("#colContainer li").length ; i++) {
(function(i) {
var el = $("#colContainer li:nth-child(" + i + ") .colContent");
setTimeout(function(){
el.slideUp();
}, i * 10);
})(i);
}
Did you want them to be queued or for a 10 millisecond delay before they all slide up?
Do you require the for loop?
Wouldn't the following do the latter?
setTimeout(function() {
$("#colContainer li .colContent").slideUp();
}, 10);
Queued slide example:
(function slideContent(index) {
$("#colContainer li:nth-child(" + index + ") .colContent").slideUp();
if ($("#colContainer li:nth-child(" + (index + 1) + ") .colContent").length == 1) {
setTimeout(function() { slideContent(index + 1); }, 250);
}
})(1);
Unless your intention is to have them all animate at the same time, you can't set them up in a loop this way. If you do, they're all executed (almost) simultaneously and as you say, you'll only actually see the last one.
You need to trigger each successive one from the completion of the previous one. Chain them together with callbacks.
delay should set up the next setTimeout. Then you'll get the result you're after.
EDIT
Given the other answers here, I'll add that you'll probably want to increase your pause time from 10ms to something like 100 and then use the *i solution that the others have suggested. Multiplying 10ms by i isn't going to get you a whole lot in the way of noticeable delay. I'd start with 100ms and if that's too jerky move down from there in increments of 10ms till you have an animation that makes you happy.
Related
I have a li that I want to animate while hovering over.
I try to get the previous li item with ยง(this).prevAll("li") and then use JQuery to change the style.
For this I want to get the IDs of the previous items. My current code looks like this:
$("#somediv li").hover(function()
{
var object = $(this).prevAll("li");
var i;
for (i = object.length - 1; i >= 0; i--) {
dowork(i);
}
function dowork(i) {
setTimeout(function() {
console.log(i);
$("#"+object[i].id+"").addClass("animateprogress");
}, 500 * i);
}
Output of the for loop is 5,4,3,2,1,0 (depending on object length). The timeout output though reverses this to 0,1,2,3,4,5. I don't know why tough. I just want to output 5,4,3,2,1,0 with 500ms delay to style my previous li elements.
You'll have to distinguish between the delay you want and the object index you want. Both are now the same variable i in your function, but they should be somewhat opposite.
So for example do:
$("#somediv li").hover(function() {
var object = $(this).prevAll("li");
var i;
for (i = 0; i < object.length; i++) {
// pass a delay that increases with each iteration,
// and pass an index that decreases with each iteration:
dowork(500 * i, object.length - 1 - i);
}
function dowork(delay, index) {
setTimeout(function() {
console.log(index);
$("#"+object[index].id).addClass("animateprogress");
}, delay);
}
});
try:
setTimeout(animate, (object.length - 1 - i) * 500)
instead.
you can use these codes too
$("#somediv li").hover(function()
{
var object = $(this).prevAll("li");
var i;
for (i = object.length - 1; i >= 0; i--) {
dowork(i,(object.length-i)*500);
}
function dowork(i,d) {
setTimeout(function() {
console.log(i);
$("#"+object[i].id+"").addClass("animateprogress");
}, d);
}
It will give the result you expect.
The issue was on delay time you was adding greater time for greater number which is opposite of your expectation
I'm trying to make a faux loading screen, and I need delays between loading messages of about 20-50ms or so so that people can actually see what's going on before it cuts to the initialized screen. The button that activates this goes to the following function:
function gameinit() {
for (k = 0; k <=1; k += 0.125) {
setTimeout(function () {
var nexttxt = "Loading... " + toString(100 * k) + "%"
}, 20);
displayupdate(nexttxt);
}
}
However this comes up as an incorrect syntax (on JSfiddle - https://jsfiddle.net/YoshiBoy13/xLn7wbg6/2/) when I use JShint - specifically lines four and five. I've looked at the guides for this and everything seems to be in order. What am I doing wrong?
(Note: displayupdate(nexttxt) updates the <p> tags with the next line of text)
When executing the script, nothing happens - the sixteen lines of text on the HTML move up as normal, the top eight being replaced with the eight generated by the gameinit() function, but the gameinit() only generates blank. If the script is executed again, it just outputs eight lines of 112.5% (as if it was the 9th iteration of the for loop).
I'm almost certain it's something elementary that I've missed, could someone please tell me what I've done wrong?
Use setInterval() instead, you can clear interval using clearInterval()
function gameinit() {
displayupdate("Loading... 0%");
var k = 0;
var inter = setInterval(function() {
if (k < 1) {
k += .25;
displayupdate("Loading... " + 100 * k + "%")
} else {
clearInterval(inter);
}
}, 2000);
}
function displayupdate(d) {
console.log(d);
}
gameinit();
here is another function can do this better ---- setInterval
var txt = '';
var time = 0;
var id = setInterval(function(){
console.log("loading..."+time/8*100+"%");
if(time++>7)
clearInterval(id);
},1000);
setTimeout doesn't work as you would expect it to work inside loops. You have to create a closure for each loop variable passed on to setTimeout, or create a new function to execute the setTimeout operation.
function gameinit() {
for (var k = 0; k <= 1; k += 0.125) {
doSetTimeOut(k);
}
}
function doSetTimeOut(k) {
setTimeout(function() {
var nexttxt = "Loading... " + toString(100 * k) + "%"
}, 20);
displayupdate(nexttxt);
}
When I click the checkBox, the function hesitates 5 seconds, and then rapidly loops through $.each skipping the setTimeout method. I assumed setTimeout would delay 5 seconds on each pass of the $.each loop? How can I make that so? Thanks
checkBox.addEventListener('click', function() {
var countLoop = 0;
$.each(placeObject, function(key,value) {
setTimeout(function() {placesSearch(key,value);}, 5000);
console.log("Loop :" + countLoop++);
});
},
false);
setTimeout returns the ID of the timeout, and does so immediately. It queues the action to be executed at a set time in the future. It won't actually pause the execution of the code it resides in, however, due to the immediate return.
If you want the code in $.each to be run after a pause, all of the code within the $.each needs to be wrapped with the setTimeout
Check this fiddle: http://jsfiddle.net/6dzp1sj7/1/
checkBox.addEventListener('click', function() {
var countLoop = 0;
$.each(placeObject, function(key,value) {
setTimeout(function() {
placesSearch(key,value);
console.log("Loop :" + countLoop++);
}, (5000 * (key + 1)));
});
},
false);
Here is some JS KungFU for you:
Here is its fiddle http://jsfiddle.net/6dzp1sj7/3/
var placeObject = [0, 1, 2, 3, 4, 5];
var countLoop = 0;
function tmp (key, value) {
console.log(key);
console.log(value);
console.log("Loop :" + countLoop++);
}
var code = "";
$.each(placeObject, function(key,value) {
var tmpl = "setTimeout(function() {tmp(" + key + ", " + value + ");__##__}, 1000);";
if (key == 0) code = tmpl;
if (key != 0) {
code = code.replace('__##__', tmpl);
}
if (key == (placeObject.length - 1)) {
code = code.replace('__##__', '');
//console.log(code);
eval(code);
}
});
Note: Never use a jack-hammer to drill just a hole.
If you want each to fire within 5 seconds of one another, i.e. first iteration fires 5 seconds later, second iteration fires 10 seconds later, etc.. Then you need to multiply the delay of each individual timeout via the count index.
var countLoop = 1;
$.each(placeObject, function(key,value) {
setTimeout(function() {placesSearch(key,value);}, 5000*countLoop);
console.log("Loop :" + countLoop++);
});
I've created a demo that also illustrates how the scope would affect the values you are printing out with console.log(). See this fiddle for an example:
http://jsfiddle.net/smtryj6s/6/
I have a for loop with a setTimeout function inside of it intended to delay each iteration of the loop. While the rest of the code within the loop is properly iterating, the setTimeout function only works once, as if the for loop was inside of it and not the other way around. Here's my code:
for (x = 0; x <= roll; x ++) {
setTimeout(function() {
space = $(".player." + turn).parents("td").attr("id");
space = parseInt(space);
player = $(".player." + turn);
$(".player." + turn).remove();
nextSpace = space + 1;
$("#" + nextSpace).append(player);
}, 500);
}
Any ideas?
Try this:
setTimeout(function() {
// your code
}, 500 * x);
This is not how setTimeout works. It is not a synchronous delay. If you want to delay each iteration of your loop, you need to instead do this by recursively calling the inner function.
function inner_function(x, max_x) {
space = $(".player." + turn).parents("td").attr("id");
space = parseInt(space);
player = $(".player." + turn);
$(".player." + turn).remove();
nextSpace = space + 1;
$("#" + nextSpace).append(player);
setTimeout(inner_function, 500, x+1, max_x);
}
inner_function(0, 500);
This is my code. What I want it to do is write 0, wait one sec, write 1, wait one sec, write 2, wait one sec, etc. Instead it writes 5 5 5 5 5
for(i = 0; i < 5; i++) {
setTimeout("document.write(i + ' ')", 1000);
}
http://jsfiddle.net/Xb7Eb/
1) You set all the timeouts to last 1 second at the same time. The loop doesn't wait for the timeout to occur. So you have 5 timeouts that all execute at the same time.
2) When the timeouts execute, the loop is long since complete and i has become 5. So once they execute, they all print "5"
3) document.write() writes somthing onto the page, in the same place it executes. I.e. if you have <script>document.write("xyz")</script> in the middle of a piece of text, it'll write "xyz" in the middle of the text. The timeouts, however, are not necessarily anywhere on the page. They exist only in code.
Here's a solution that's as close to yours as possible: http://jsfiddle.net/rvbtU/1/
var container = document.getElementById("counter");
for(i = 0; i < 5; i++) {
setTimeout("container.innerHTML += '" + i + " ';", 1000 * i);
}
However, that solution uses setTimeout's ability to evaluate a string as javascript, which is never a good idea.
Here's a solution that uses an anymous function instead: http://jsfiddle.net/YbPVX/1/
var container = document.getElementById("counter");
var writer = function(number) {
return function() { container.innerHTML += String(number) + " "; };
}
for(i = 0; i < 5; i++) {
setTimeout(writer(i), 1000 * i);
}
Edit: Forgot to save the 2nd fiddle. Whoops. Fixed now.
Most of the answers available are giving bad advice.* Specifically, you shouldn't be passing a string to setTimeout anymore (it still works, but it's discouraged), it's no longer 2000, there are better ways to do this.
setTimeout takes a function as the first parameter, and that's what you should do, however there are some issues when calling setTimeout in a loop.
This looks like it should work:
var i;
for ( i = 0; i < 5; i++ )
{
setTimeout(function(){
document.write( i + ' ' );
}, 1000 * (i + 1) );
}
But it doesn't. The issue is that by the time setTimeout executes the function, the loop will have incremented i to 5, so you'll get the same value repeated.
There are a few fixes. If you're willing to risk a with statement, you could try the following:
var i;
for ( i = 0; i < 5; i++ )
{
with( { i:i } )
{
setTimeout(function(){
document.write( i + ' ' );
}, 1000 * (i+1) );
}
}
Note that with is typically discouraged just like passing string values to setTimeout, so I don't really suggest this method of doing things.
The better way is to use a closure:
var i;
for ( i = 0; i < 5; i++ )
{
(function(i){
setTimeout(function(){
document.write( i + ' ' );
}, 1000 * (i+1) );
})(i);
}
To explain what's going on, the anonymous function wrapper (function(i){...code...}) executes immediately because it's wrapped in parens and passed i as a value:
(function(i){...code...})(i);
This forces the i variable that document.write uses to be a different one than what's being used in the for loop. You could even change the parameter used in the anonymous function wrapper if the difference gets too confusing:
(function(a){document.write(a+' ')})(i);
* when I started writing this question there were a number of answers describing how to fix the string to work with setTimeout, although they would technically work, they didn't include why they would work (because 'document.write("' + i + ' ");' evaluates i at the time of calling due to string concatenation, versus evaluating i at runtime like the previous version did), and they most certainly didn't mention that it's the bad old way of calling setTimeout.
try
var i = 1;
function timeout(){
document.write(i + ' ');
i++;
if (i == 5) return;
setTimeout(timeout, 1000);
}
timeout();
http://jsfiddle.net/nnJcG/1/
You have a problem with clousures, you can try this:
var timeout = function(){
var i = 0;
return function(){
document.write(i+ ' ');
i++;
if(i!==5)
setTimeout(timeout,1000);
};
}();
setTimeout(timeout,1000);
Here is the example in jsBin http://jsbin.com/uloyuc/edit
First of all, NEVER pass a string to setTimeout. Use a function, it's much cleaner.
Second, you have to "close over" the loop value. I bet this is what you want.
for(var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() {
document.write(i + ' ')
}, i * 1000);
}(i));
}
See more about you a self executing function to close over a loop value here http://www.mennovanslooten.nl/blog/post/62
And just cause I love it, here is the equivalent in CoffeeScript whihc has the do keyword to help out with just this case.
for i in [0..4]
do (i) ->
setTimeout ->
document.write "#{ i } "
, i * 1000
You can also work with setInterval and clearInterval:
var i = 0;
var f = setInterval(function() {
if(i == 4) clearInterval(f);
document.write(++i + ' ');
}, 1000);
I think this code is very readable.
You could try like this:
var tick_limit = 5; // Or any number you wish representing the number of ticks
var counter = 0; // Or any number you wish
var timer_interval = 1000; // Interval for the counter
var timer;
function timerTick()
{
if(counter < tick_limit)
{
// Execute code and increase current count
document.body.innerHTML+=(counter + ' '); // Append the counter value to the body of the HTML page
counter++;
timer = setTimeout(timerTick,timer_interval);
}
else
{
// Reset everything
clearTimeout(timer);
counter = 0;
}
}
function startCounter()
{
clearTimeout(timer); // Stop current timer
timer = setTimeout(timerTick,timer_interval); // Start timer with any interval you wish
}
...
// Start timer when required
startCounter();
...
This way, calling the startCounter a number of times will result in a single timer executing the code
You're triggering five timeouts at the same time.
I like Pindatjuh's answer, but here's another fun way to do it.
This way starts the next timeout when the previous one is finished:
// Wrap everything in a self executing anonymous function so we don't pollute
// the global namespace.
//
// Note: Always use "var" statments or you will pollute the global namespace!
// For example "for(i = 0; i < 5; i++)" will pollute the global namespace
// unless you have "var i; for(i = 0; i < 5; i++)" or
// "for(var i = 0; i < 5; i++)" & all of that is not in the global namespace.
//
(function() {
// "i" will be available within doThis()
// you could also pass "i" as an argument
var i = 0,
doThis = function() {
// setTimeout can take an anonymous function
// or a regular function. This is better than
// eval-ing a string.
setTimeout(function() {
document.write(i + ' ');
++i;
// Do the function again if necessary
if (i < 5) doThis();
}, 1000);
}
// Let's begin!
doThis();
})();
Working Example