A better approach would be to delegate the event, which means catching it as it bubbles to the parent node.
This solution is both more robust and efficient.
It allows the event to be handled even if more rows are dynamically added to the table later, and also results in attaching a single event handler to the parent node (table
element), instead of one for each child node (tr
element).
Assuming that the OP's example is a simplified one, the table's structure can be more complex, for example:
<table id="indexedTable">
...
<tr>
<td><p>1</p></td>
<td>2</td>
<td><p>3</p></td>
</tr>
</table>
Therefore, a simplistic approach such as getting e.target.parentElement
will not work, as clicking the internal <p>
and clicking the center <td>
will produce different results.
Using delegation normalizes the event handling, only assuming that there are no nested tables.
Both of the following snippets are equivalent:
$("#indexedTable").delegate("tr", "click", function(e) {
console.log($(e.currentTarget).index() + 1);
});
$("#indexedTable").on("click", "tr", function(e) {
console.log($(e.currentTarget).index() + 1);
});
They attach a listener to table
element and handle any event that bubbles from the table rows. The current API is the on
method and the delegate
method is legacy API (and actually calls on
behind the scenes).
Note that the order of parameters to both functions is different.
A comparison between direct handler attachment and delegation is available below or on jsFiddle:
$("#table-delegate").on("click", "tr", function(e) {_x000D_
var idx = $(e.currentTarget).index() + 1;_x000D_
$("#delegation-idx").text(idx); _x000D_
console.log('delegated', idx);_x000D_
});_x000D_
_x000D_
$("#table-direct tr").on("click", function(e) {_x000D_
var idx = $(e.currentTarget).index() + 1;_x000D_
$("#direct-idx").text(idx);_x000D_
console.log('direct', idx);_x000D_
});_x000D_
_x000D_
$('[data-action=add-row]').click(function(e) {_x000D_
var id = e.target.dataset.table;_x000D_
$('#' + id + ' tbody')_x000D_
.append($('<tr><td>extra</td><td>extra</td><td>extra</td></tr>')[0])_x000D_
});
_x000D_
tr:hover{_x000D_
background:#ddd;_x000D_
}_x000D_
_x000D_
button.add-row {_x000D_
margin-bottom: 5px;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>_x000D_
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>_x000D_
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>_x000D_
_x000D_
_x000D_
<h1>Event handling test</h1>_x000D_
<p>Add rows to both tables and see the difference in handling.</p>_x000D_
<p>Event delegation attaches a single event listener and events related to newly added children are caught.</p>_x000D_
<p>Direct event handling attaches an event handler to each child, where children added after the inital handler attachment don't have a handler attached to them, and therefore their indices won't be logged to console.</p>_x000D_
<h2>Delegation</h2>_x000D_
<p><span>row index: </span><span id="delegation-idx">unknown</span></p>_x000D_
<button class="add-row" data-action="add-row" data-table="table-delegate">Add row to delegation</button>_x000D_
<table id="table-delegate" class="table">_x000D_
<tbody>_x000D_
<tr>_x000D_
<td>normal</td>_x000D_
<td>normal</td>_x000D_
<td>normal</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td><p>nested</p></td>_x000D_
<td><p>nested</p></td>_x000D_
<td><p>nested</p></td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>normal</td>_x000D_
<td>normal</td>_x000D_
<td><p>nested</p></td>_x000D_
</tr>_x000D_
_x000D_
</table>_x000D_
_x000D_
<h2>Direct attachment</h2>_x000D_
<p><span>row index: </span><span id="direct-idx">unknown</span></p>_x000D_
<button class="add-row" data-action="add-row" data-table="table-direct">Add row to direct</button>_x000D_
<table id="table-direct" class="table">_x000D_
<tbody>_x000D_
<tr>_x000D_
<td>normal</td>_x000D_
<td>normal</td>_x000D_
<td>normal</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td><p>nested</p></td>_x000D_
<td><p>nested</p></td>_x000D_
<td><p>nested</p></td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>normal</td>_x000D_
<td>normal</td>_x000D_
<td><p>nested</p></td>_x000D_
</tr>_x000D_
_x000D_
</tbody>_x000D_
</table>
_x000D_
Here's the demo on jsFiddle.
P.S:
If you do have nested tables (or, in the general case, wish to delegate to elements with specific depth), you can use this suggestion from the jQuery bug report.