Soul Soul - 6 months ago 8
Javascript Question

Logging Which Cell in Table Array Has Been Clicked With Event Listener

Perhaps a silly question, but I'm just starting to learn JS.

How would I log which table cell has been clicked with the following code (as an example).



// Get array of td elements; 9 cells for game board
var board = document.getElementsByTagName("td");
for (var i = 0; i < board.length; i++) {
console.log(board[i]);
board[i].addEventListener("click", function() {
console.log(board[i]);
console.log(i);
});
}

<!DOCTYPE html>
<html>

<body>



<table border="1">
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td>5</td>
<td>6</td>
</tr>
<tr>
<td>7</td>
<td>8</td>
<td>9</td>
</tr>
</table>

</body>

</html>





Loggin either board[i] or [i] don't work; I always comes up as 9, and board[i] comes up undefined.

EDIT: Doing some digging, I managed to stumble across some things and throw them together to make them work.

I still don't honestly understand how it works, though.

function testf(i) {
return (function(){
console.log("you clicked region number " + i);
});
}
// Trigger function cellClicked() when any table cell is clicekd
for (var i = 0; i < board.length; i++) {
board[i].addEventListener("click", testf(i));
}

Answer

What you are misinterpreting is that the statement variable i is block scoped. But variables initialized with var in JavaScript are function scoped. So at the time the event is fired the variable i is 9, because the loop is finished.

With ES2015 you can replace var with let and you are done, because let initializes a variable with block scope:

for (let i = 0; i < board.length; i++) {
  console.log(board[i]);
  board[i].addEventListener("click", function() {
    console.log(board[i]);
    console.log(i);
  });
}

But this only works in new Browsers or when you are transpiling your code to ES5 with babel for example.

You have to introduce a new scope for the i to keep the value of i for each iteration to make it work without let

function handleClick(i) {
  // function sets new scope for i
  return function() {
    console.log(board[i]);
    console.log(i);
  }
}

for (let i = 0; i < board.length; i++) {
  console.log(board[i]);
  board[i].addEventListener("click", handleClick(i));
}
Comments