How to addEventListener to table cells

It seems your canvas is overlapping your table. Because of that td elements in your table are never clicked.

You will need to add CSS property pointer-events:none to your canvas.

#myCan {
    ...
   pointer-events: none;
}

This way it won't block table from being clicked anymore.

You can also add event listeners to your cells way simpler:

document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", function() {
    // Here, `this` refers to the element the event was hooked on
    console.log("clicked")
}));

That creates a separate function for each cell; instead, you could share one function without losing any functionality:

function clickHandler() {
    // Here, `this` refers to the element the event was hooked on
    console.log("clicked")
}
document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", clickHandler));

Some browsers still don't have forEach on the HTMLCollection returned by querySelectorAll, but it's easily polyfilled:

if (!HTMLCollection.prototype.forEach) {
    Object.defineProperty(HTMLCollection.prototype, "forEach", {
        value: Array.prototype.forEach
    });
}

If you have to support truly obsolete browsers that don't have Array.prototype.forEach, see the polyfill on MDN.


This is a case for event delegation: Hook the click event on the table (or table body), not individual cells, and then determine which cell was clicked by looking at event.target and its ancestors.

Simplified example:

document.querySelector("#my-table tbody").addEventListener("click", function(event) {
  var td = event.target;
  while (td !== this && !td.matches("td")) {
      td = td.parentNode;
  }
  if (td === this) {
      console.log("No table cell found");
  } else {
      console.log(td.innerHTML);
  }
});

Live Copy:

document.querySelector("#my-table tbody").addEventListener("click", function(event) {
  var td = event.target;
  while (td !== this && !td.matches("td")) {
      td = td.parentNode;
  }
  if (td === this) {
      console.log("No table cell found");
  } else {
      console.log(td.innerHTML);
  }
});
table, td, th {
  border: 1px solid #ddd;
}
table {
  border-collapse: collapse;
}
td, th {
  padding: 4px;
}
<table id="my-table">
  <thead>
    <tr>
      <th>First</th>
      <th>Last</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Joe</td>
      <td>Bloggs</td>
    </tr>
    <tr>
      <td>Muhammad</td>
      <td>Abdul</td>
    </tr>
    <tr>
      <td>Maria</td>
      <td>Gonzales</td>
    </tr>
  </tbody>
</table>

Note that instead of the loop you could use the new (experimental) closest method on elements:

var td = event.target.closest("td");

...but A) It's still experimental, and B) It won't stop when it reaches the tbody, so in theory if you had nested tables, would find the wrong cell.

If you need to support browsers that don't have Element.prototype.matches, in this specific case you could use td.tagName !== "TD" instead of !td.matches("td") (note the capitalization).