1

My case:

var tds = document.getElementsByTagName("td");
for(i=0;i<tds.length;i++)
{
    tds[i].onclick = function()
                      {
                          alert(i);
                      };
}

Expected outcome: Alert the number of TD.

However if there are 6 TDs, the returned value will always be the last value of "i". (6) How could i make the "i" value to remain at it's value when added to the function?

Thanks!

http://jsfiddle.net/nuKEK/11/

Adam Voga
  • 124
  • 9
  • 2
    possible duplicate of [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Joe Enos Oct 30 '13 at 17:57
  • 1
    Just a note: your fiddle's JS uses `.getElementsByTagname`, which is a misspelling of `.getElementsByTagName` (capitalized `Name` at the end). The misspelling causes an error. – ajp15243 Oct 30 '13 at 17:59

5 Answers5

3

You need to make a closure to capture the i value. Something like this

function createFunction(i){
    return function(){
        alert(i);
    };
}

var tds = document.getElementsByTagName("td");
for(i=0;i<tds.length;i++){
    tds[i].onclick = createFunction(i);
}

DEMO: http://jsfiddle.net/nuKEK/12/

gen_Eric
  • 223,194
  • 41
  • 299
  • 337
1

You can pass i to another function in order to get its value rather than a reference to it. In javascript, numbers are passed by value.

tds[i].onclick = (function(x) {
    return function() {
        alert(x); // alerting x, i's value
    };
})(i); // passing i as parameter x

If that self-executing anonymous function looks a little hairy in the context of your loop, you could try Array.prototype.forEach() instead:

[].forEach.call(document.getElementsByTagName("td"), function(td, i) {
    td.onclick = function() {
        alert(i);
    };
});

[edit] Have a look at these options and their performance.

canon
  • 40,609
  • 10
  • 73
  • 97
0

This is one of the common mistakes in Javascript in that it is not block scoped like most languages. It is function-scoped.

You need to create a closure around the onclick to achieve this.

for (i = 0; i < tds.length; i++) {

    (function (index) {
        tds[index].onclick = function() {
            alert(index);
        };
    })(i);

}
Mark Pieszak - Trilon.io
  • 61,391
  • 14
  • 82
  • 96
0
var tds = document.getElementsByTagName("td");
for(i=0;i<tds.length;i++)
{
    addClick(tds, i);
}


function addClick(where, i) {
    where[i].onclick = function()
    {
        alert(i);
    };
}
dezman
  • 18,087
  • 10
  • 53
  • 91
0

You will have to force the value into a scope that will still exist when the callback is fired.

for(i=0;i<tds.length;i++){
  (function(){
    var _i = i;
    tds[i].onclick = function(){
      alert(_i);
    };
  })();
}

Otherwise, the value for i will always be the last index

posit labs
  • 8,951
  • 4
  • 36
  • 66