zEn feeLo
zEn feeLo

Reputation: 1978

setTimeout passing arguments issue

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 ??

Upvotes: 0

Views: 299

Answers (4)

JonWarnerNet
JonWarnerNet

Reputation: 1172

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);

Upvotes: 2

Yevgeny Simkin
Yevgeny Simkin

Reputation: 28349

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.

Upvotes: 0

Alex D
Alex D

Reputation: 189

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);
}

Upvotes: 6

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324620

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); }

Upvotes: 7

Related Questions