Pierre de LESPINAY
Pierre de LESPINAY

Reputation: 46198

How to pass 'this' into a setTimeout callback

css

.item {
  display: none;
}

html

<div>
  <div class="item">machin</div>
  <div class="item">chose</div>
  <div class="item">chouette</div>
  <div class="item">prout</div>
</div>

I'm using jQuery and I'd like to make each .item appearing after a random little timer like:

javascript

$('.item').each(function () {
  itm = $(this);
  setTimeout(function () {
    itm.fadeIn(1000);
  }, Math.floor(Math.random() * 1000));
})

Here itm will always contain the last item because the function is evaluated after all assignments.
I can't use the 3rd parameter of setTimeout() because it will not work on IE.
It's not advised to use setTimeout() with the eval method for security reasons.

So how can I access to my object through setTimeout() ?


Edit

I know that this question have already been posted.
But I though that it were slightly specific with the each() context.
Now someone have entirely changed the title of my question that was originally something like 'setTimeout() - jQuery.each() this object parameter'

Upvotes: 9

Views: 3598

Answers (8)

Alex
Alex

Reputation: 35407

Create/Utilize a closure:

$('.item').each(function () {
  var that = this;

  setTimeout(function () {
    $(that).fadeIn(1000);
  }, Math.floor(Math.random() * 1000));
})

http://jibbering.com/faq/notes/closures/

https://developer.mozilla.org/en/JavaScript/Guide/Closures

Upvotes: 13

georg
georg

Reputation: 215009

Do not use setTimeout, use jQuery own tools.

$('.item').each(function () {
   $(this).delay(Math.random() * 1000).fadeIn();
})

http://api.jquery.com/delay/

Working example: http://jsfiddle.net/qENhd/

Upvotes: 15

ShankarSangoli
ShankarSangoli

Reputation: 69915

Before setTimeout executes each loop would have finished executing, it will not wait. Also inside setTimeout function this will not refer to the DOM element.

Try something like this.

function fadeItem(item){
   item.fadeIn(1000);
}

$('.item').each(function () {
  var $item = $(this);
  setTimeout(function () {
    fadeItem($item);
  }, Math.floor(Math.random() * 1000));
});

You can also try something like this.

var $items = $('.item'), count = 0;

function fadeItem(item){
   item.fadeIn(1000);
    if(count < $items.length){
       setTimeout(function(){
            fadeItem($items.eq(count++));
       }, Math.floor(Math.random() * 1000));
    }
}
setTimeout(function(){
    fadeItem($items.eq(count++));
}, Math.floor(Math.random() * 1000));

Upvotes: 3

Kyle
Kyle

Reputation: 3609

Try this:

 $('.item').each(function () {
    var item =$(this);
    setTimeout(function () {
            item.fadeIn(1000);
        },
        Math.floor(Math.random() * 1000));
   });

Upvotes: 2

Simon Edstr&#246;m
Simon Edstr&#246;m

Reputation: 6619

Try this insteed:

    $('.item').each(function () {
        var elm = this;
      setTimeout(function () {
        $(elm).fadeIn(1000);
      }, Math.floor(Math.random() * 1000));
    })

I can't explain why it works, but i think this is a reference to another "this" in your setTimeout.

http://jsfiddle.net/Pdrfz/

Upvotes: 2

Ninja
Ninja

Reputation: 5152

Try this:

$('.item').each(function () {
 var myVar = $(this);
setTimeout(function () {
myVar.fadeIn(1000);
}, Math.floor(Math.random() * 1000));
})

Upvotes: 2

JaredPar
JaredPar

Reputation: 755121

The trick here is to save this into a local that can be evaluated safely in the setTimeout callback

$('.item').each(function () {
  var self = this;
  setTimeout(function () {
    $(self).fadeIn(1000);
  }, Math.floor(Math.random() * 1000));
});

Upvotes: 2

SLaks
SLaks

Reputation: 887767

You need to store this in a separate variable:

$('.item').each(function () {
  var me = $(this);
  setTimeout(function () {
    me.fadeIn(1000);
  }, Math.floor(Math.random() * 1000));
})

Upvotes: 2

Related Questions