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?
The reason why this happens is because Javascript is single threaded.
Clicking the Stop button clears the timer by using the clearInterval(), passing in the 'check' variable that is returned by the call to setInterval(). The last step is to reset the value of the counter to '0'.
setTimeout allows us to run a function once after the interval of time. setInterval allows us to run a function repeatedly, starting after the interval of time, then repeating continuously at that interval.
Have variable 'myID' local to the anonymous function,
var myID = $(this).attr('id');
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]);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With