views:

82

answers:

3

I'm using jQuery to setup a timer or interval loop on a few elements to check them every couple seconds. I've tried setting a timer and checking if I should restart it, or setting and interval and checking if I should stop it.

Although simplified, this is basically what I need:

var mytimers = new Array();
$('div.items').each(function() {
    myID = $(this).attr('id');
    mytimers[myID] = setInterval( function() { myFunction(myID) } , 3000)
});
function myFunction(param) {
    alert(param);
    if (something()) {
        clearInterval(mytimers[param]);
    }
}

The ID's for class items are id_1, id_2, id_3. But I simply get 3 alerts all giving id_3. In my code I started off trying to pass 'this', but kept simplifying it to figure out the issue.

How can I get it to copy the variable to a new address each time? I know I need to use closures. It seems to be referencing the other var no mater what.

I tried simplifying it to a loop with timers like so:

function tester(item) {
    return function() {
        alert(item);
    };
}
for(x=1;x<=3;x++) {
    setTimeout( '(function() { tester(x) })(x)' , 3000);
}

But I think I'm just making my problem worse and that doesn't seem to do anything.

I've searched for previous questions, but most are filled with tons of extra code rather than cutting it down the the specific issue and are solved in some other manner. I'd like to understand how this works better by getting this example working. I did manage, while writing this, to figure out I can set off the timer with a helping function.

function tester(item)
    alert(item);
function myTimer(item)
    setInterval( function() { tester(item); }, 3000);
for(x=1;x<=3;x++)
    myTimer(item);

How can this be done without that? Is there some better way?

+3  A: 

Have variable 'myID' local to the anonymous function,

var myID = $(this).attr('id');
Marimuthu Madasamy
A: 

You're in a closure when you use each, you just have forgotten var to make your variable private in the function scope

var mytimers = new Array();
$('div.items').each(function() {
    **var** myID = $(this).attr('id'); 
    mytimers[myID] = setInterval( function() { myFunction(myID) } , 3000)
});
function myFunction(param) {
    alert(param);
    if (something()) {
        clearInterval(mytimers[param]);
    }
}
eskimoblood
*smacks forehead* I actually tried var in all sorts of places, except that one, ha.
phazei
A: 

So you want to run myFunction on each of the matched elements every three seconds?

Try this:

$('div.items').each( myFunction(this) );

var myFunction = function(elem) {
    return function() {
        if ( something(elem) ) {
            //return or do something with elem
        } else {
            window.setTimeout( myFunction(elem), 3000 );
        }
    }
};

If the condition in something() is met you're done, if not the function schedules itself to run again in 3 seconds with the same element as before. You can call this as many times as you want on different elements, each call has its own elem.

I prefer to pass objects like elem around and delay working with their internals until the last possible moment. Let something() worry about the id or whatever.

None of the other gymnastics with the associative array (instead of new Array() you could just use {}), or clearInterval, or ID's are necessary.

To actually address your solution, as Marimuthu said, you left var off the declaration of myID, which means its global and it gets overwritten each iteration. The result is that when setInterval invokes myFunction instead of getting a unique local myID via closure, you get the global one that has already been overwritten umpty times.

jasongetsdown