<table id="position">
<tr><td>TL</td><td>TC</td><td>TR</td></tr>
<tr><td>CL</td><td>CC</td><td>CR</td></tr>
<tr><td>BL</td><td>BC</td><td>BR</td></tr>
</table>
<script>
document.querySelector("#position td").addEventListener("click", function(){
console.log(this.innerHTML);
});
Trying to get innerHTML of table cell <td>
on click. It returns nothing. When I change selector to #position tr
it returns data, but ONLY for first <tr>
row, when I click on it. When clicking on second, third - returns nothing. Obviously, when I change selector to table #position
it works fine and returns whole table.
I even tried to add class for every cell like <td class="cell">
- document.querySelector(".cell").innerHTML
returns content, but once again - ONLY for first <td>
cell!
How to get clicked td
and why is it behaving so strange? Also, is it possible to get clicked row/column number?
<table id="position">
<tr><td>TL</td><td>TC</td><td>TR</td></tr>
<tr><td>CL</td><td>CC</td><td>CR</td></tr>
<tr><td>BL</td><td>BC</td><td>BR</td></tr>
</table>
<script>
document.querySelector("#position td").addEventListener("click", function(){
console.log(this.innerHTML);
});
Trying to get innerHTML of table cell <td>
on click. It returns nothing. When I change selector to #position tr
it returns data, but ONLY for first <tr>
row, when I click on it. When clicking on second, third - returns nothing. Obviously, when I change selector to table #position
it works fine and returns whole table.
I even tried to add class for every cell like <td class="cell">
- document.querySelector(".cell").innerHTML
returns content, but once again - ONLY for first <td>
cell!
How to get clicked td
and why is it behaving so strange? Also, is it possible to get clicked row/column number?
3 Answers
Reset to default 14Add a single listener to the tbody of the table, and retrieve the clicked cell from the event object, like this:
const tbody = document.querySelector('#position tbody');
tbody.addEventListener('click', function (e) {
const cell = e.target.closest('td');
if (!cell) {return;} // Quit, not clicked on a cell
const row = cell.parentElement;
console.log(cell.innerHTML, row.rowIndex, cell.cellIndex);
});
<table id="position">
<tr>
<td>TL</td>
<td>TC</td>
<td>TR</td>
</tr>
<tr>
<td>CL</td>
<td>CC</td>
<td>CR</td>
</tr>
<tr>
<td>BL</td>
<td>BC</td>
<td>BR</td>
</tr>
</table>
This technique is called event delegation, it takes the advantage of the event bubbling mechanism, where the events are fired on every ancestor element of the actual clicked element too. It's very useful, specifically when working with dynamic tables, and is handy to use with static tables as well.
As you can see (in the console.log
), table rows and cells have a specific row/cellIndex
property. It's dynamic, and you can use those properties to get the "row/column number".
querySelector()
only selects the first element with that selection criteria. You will need to use querySelectorAll()
to select all table cells. This would return a nodelist. You will then have to iterate through the nodelist and attach the click listener to all nodes.
var cells = document.querySelectorAll("#position td");
for (var i = 0; i < cells.length; i++) {
cells[i].addEventListener("click", function() {
console.log(this.innerHTML);
});
}
<table id="position">
<tr>
<td>TL</td>
<td>TC</td>
<td>TR</td>
</tr>
<tr>
<td>CL</td>
<td>CC</td>
<td>CR</td>
</tr>
<tr>
<td>BL</td>
<td>BC</td>
<td>BR</td>
</tr>
</table>
you can easily do it like this,
function runMe(text){
console.log(text);
}
<table id="position">
<tr><td onclick="runMe(this.innerHTML)">TL</td><td onclick="runMe(this.innerHTML)">TC</td><td onclick="runMe(this.innerHTML)">TR</td></tr> </table>
querySelector()
only gives you the first match of the selector,querySelectorAll()
gives you all of them. use the latter and loop over all element to attach the handler. Alternatively, attach a handler to the table as a whole and check the specific target cell. – Sirko Commented Jun 8, 2020 at 9:45