views:

32

answers:

2

I'm trying to get the "click()" function to display the value of 'i' at the time I passed in the function. But its referring back to the value of 'i' after it finished. I'm drawing a blank on how to get the function to refer to the value of 'i' when I first passed the function in.

for( var i=0; i<10; i++){
 var ts = $('#<span></span>').clone().click(function(){
  alert(i);
 });
}

NOTE:

The '#' shouldn't be there, neither should the '.clone()'

+2  A: 

You need to move the body of the loop to a separate function that takes i as a parameter.

You can use a normal function, like this:

for(var i=0; i<10; i++) {
    makeCopy(i);
}

function makeCopy(i) { 
    var ts = $('#<span></span>').clone().click(function(){
        alert(i);
    });
}

You can also use an inline method, like this: (beware confusing syntax)

for(var i=0; i<10; i++) {
    (function(i) { //Note i parameter
        var ts = $('#<span></span>').clone().click(function(){
            alert(i);
        });
        ...
    })(i);         //Note i parameter
}
SLaks
Your second approach will alert `10` in all cases.
Nick Craver
@Nick: ​​​​Why?
SLaks
@SLaks - Because `i` still refers to the same outer variable, you can test it here: http://jsfiddle.net/nick_craver/ruHjJ/1/ You have to pass `i` into the function to get a copy.
Nick Craver
You're right; I forgot about that. Fixed
SLaks
For clarity of example I'd rename the variable inside the function, but as it is it'll work :)
Nick Craver
Technically it would have alerted `undefined`, as `i` was used inside and outside.
patrick dw
+3  A: 

Something like this will work:

for(var i=0; i<10; i++){
  (function(j) {
    var ts = $('<span></span>').click(function(){
        alert(j);
    });
  })(i);
}

You can give it a try here. Though, your creation is a bit off, I'm not sure why you'd want to create a new element just to clone it, and there's an extra # in there....I removed both of these above, but it doesn't affect the solution of an inner function.

Nick Craver
This is the correct answer; wrapping the event handler in an anonymous function and passing it i produces the desired closure.
Clay Hinson
Hey Nick, I thought I read somewhere that jQuery saves an element once you make it so you have to clone it if you want a new one. I'm hazy even on the memory though, so thats probably wrong.
DutrowLLC
@DutrowLLC - It does, if the HTML string used to create it is shorter than 512 bytes, then the document fragment it creates is cached, but *that* is cloned already (for speed) so you don't need ti do it yourself :)
Nick Craver