I have this code (opt1) to get the text of the cell, which is clicked, but this alerts all of the objects in the table as its in a loop. But when I place it outside the loop I just get a random text from the table and not the one which is clicked (opt2).
I need the textContent of the cell, which is clicked, once, and not any other.
FYI: the cell contains multiple <td>
inside <tr>
.
The current method gets me the name text either of all cells (opt1) or the last cell (opt2)
HTML:
<table id="table"> <tr class="cell" onclick="RowHandlers()"> <td class="name">Name</td> <td class="date">Date</td> <td class="subject">Subject</td> </tr> </table>
opt1
function RowHandlers() { var table = document.getElementById("table"); var name; for (var i=1;i<table.rows.length;i++) { name = table.rows[i].cells[0].innerText; alert(name); } }
opt2
function RowHandlers() { var table = document.getElementById("table"); var name; for (var i=1;i<table.rows.length;i++) { name = table.rows[i].cells[0].innerText; } alert(name); }
Advertisement
Answer
Your problem seems to be identifying the clicked row after a click has happened.
We can solve this in multiple ways:
- In JS, use the event object‘s
target
property:- (Preferred) Add handler via
addEventListener()
.- Use a single handler by making use of event propagation.
- Add handlers to each row.
- (Discouraged) Add handler via
onevent
property. Only one handler can be added this way. - (Deprecated) Use the global object
window.event
.
- (Preferred) Add handler via
- (Discouraged) In HTML, use inline event
onclick
on each row:- Pass
this
to the handler function (e.g.<tr onclick="RowHandler(this)">
).this
in inline events will refer to the clicked element. - Add IDs to each row (e.g.
<tr id="row1">
). For each row, pass its ID to the function (e.g.onclick="RowHandler('row1')"
). Search for the element by the passed ID.
- Pass
Using addEventListener()
To add a listener, pass the event type and the listener:
const input = document.querySelector("input"); const button = document.querySelector("button"); button.addEventListener("click", clickHandler); function clickHandler(event) { console.log(input.value); input.value = ""; }
<input><button>Click me!</button>
Event propagation
Because events bubble up the DOM, <table>
‘s listener will also fire when its rows are clicked. We can use event.target
to get the event’s origin element and find the clicked row:
const table = document.querySelector("table"); table.addEventListener("click", tableClickHandler); function tableClickHandler(event) { const row = event.target.closest("tr.cell"); // event.target may be a <td> const isInRow = Boolean(row); const isFirstRow = row === table.rows[0]; if (!isInRow || isFirstRow) return; const name = row.cells[0].textContent; const date = row.cells[1].textContent; const subject = row.cells[2].textContent; console.log("Clicked:", { name, date, subject }); }
table,td{border:1px solid}
<table> <tr> <th>Name</th> <th>Date</th> <th>Subject</th> </tr> <tr class="cell"> <td class="name">Some name</td> <td class="date">01-01-1999</td> <td class="subject">Some subject</td> </tr> <tr class="cell"> <td class="name">Another name</td> <td class="date">02-02-2020</td> <td class="subject">Another subject</td> </tr> </table>
Regarding your solutions
You are missing some way of identifying the clicked element; see my suggestions above.
In opt2, you are looping through all rows, but constantly overriding the variable name
before using it. Therefore it is the same as only reading the name of the last row.
You may want to use .textContent
over .innerText
, because it doesn’t cause a reflow. If visibility of the content matters, choose .innerText
, otherwise .textContent
.
A table usually consists of sections (e.g. <thead>
, <tbody>
, <tfoot>
, or an implicit section). Each section consists of rows; each row consists of cells. Therefore, your class name "cell"
for a row may be confused with actual table cells (<td>
/<th>
).