What's happening
The variable td
is defined outside of your event handlers, so when you click on a cell you are logging the last value it was set to.
More technically: each event handler function is a closure—a function that references variables from an outer scope.
The general solution
The general solution to this kind of problem is to return the event handler from a wrapper function, passing the variables you want to "fix" as arguments:
td.addEventListener('click', function(wrapTD) {
return function() { console.log(wrapTD); }
}(td));
The arguments are now bound to the scope of the invoked wrapper function.
Simpler solution: use this
There's an even simpler option, however. In an event handler, this
is set to the element on which the handler is defined, so you can just use this
instead of td
:
td.addEventListener('click', function() {
console.log(this);
});
Even simpler: no loop!
Finally, you can get rid of the for
loop entirely and set a single event handler on the whole table:
var table = document.getElementById('my-table');
table.addEventListener('click', function(e) {
if (e.target.nodeName.toUpperCase() !== "TD") return;
var td = e.target;
console.log(td);
});
This is a much better solution for larger tables, since you are replacing multiple event handlers with just one. Note that if you wrap your text in another element, you will need to adapt this to check if the target element is a descendant of a td
.