次のような表があります。
<table>
<tr>
<td>1</td><td>1</td><td>1</td>
</tr>
<tr>
<td>2</td><td>2</td><td>2</td>
</tr>
<tr>
<td>3</td><td>3</td><td>3</td>
</tr>
</table>
ユーザーがテーブルをクリックすると、この行のインデックス(tr
要素)を取得できますか?
たとえば、最初のtr
(上記の表の1
s)をクリックすると、それが選択されて1
が返されます。
これにより、クリックされた行のインデックスが1から始まります:
$('#thetable').find('tr').click( function(){
alert('You clicked row '+ ($(this).index()+1) );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="thetable">
<tr>
<td>1</td><td>1</td><td>1</td>
</tr>
<tr>
<td>2</td><td>2</td><td>2</td>
</tr>
<tr>
<td>3</td><td>3</td><td>3</td>
</tr>
</table>
各行の最初のセルに格納されている数値を返したい場合:
$('#thetable').find('tr').click( function(){
var row = $(this).find('td:first').text();
alert('You clicked ' + row);
});
より良いアプローチは、イベントを委任することです。つまり、イベントが親ノードにバブルするときにキャッチすることを意味します。
このソリューションは、より堅牢で効率的です。
後でテーブルにさらに行が動的に追加された場合でもイベントを処理できます。また、各子ノード(table
要素)ではなく、単一のイベントハンドラーを親ノード(tr
要素)にアタッチします。
OPの例が単純化されたものであると仮定すると、テーブルの構造はより複雑になる可能性があります。次に例を示します。
<table id="indexedTable">
...
<tr>
<td><p>1</p></td>
<td>2</td>
<td><p>3</p></td>
</tr>
</table>
したがって、e.target.parentElement
を取得するなどの単純なアプローチは機能しません。内部<p>
をクリックし、中央の<td>
をクリックすると異なる結果が生成されるためです。
委任を使用すると、ネストされたテーブルがないことを前提としてのみ、イベント処理が正規化されます。
次のスニペットはどちらも同等です:
$("#indexedTable").delegate("tr", "click", function(e) {
console.log($(e.currentTarget).index() + 1);
});
$("#indexedTable").on("click", "tr", function(e) {
console.log($(e.currentTarget).index() + 1);
});
それらはtable
要素にリスナーをアタッチし、テーブル行からバブルするイベントを処理します。現在のAPIはon
メソッドであり、delegate
メソッドはレガシーAPIです(そして実際にはon
を舞台裏で呼び出します)。
両方の関数のパラメーターの順序が異なることに注意してください。
ハンドラーの直接接続と委任の比較は、jsFiddleの下または上にあります。
$("#table-delegate").on("click", "tr", function(e) {
var idx = $(e.currentTarget).index() + 1;
$("#delegation-idx").text(idx);
console.log('delegated', idx);
});
$("#table-direct tr").on("click", function(e) {
var idx = $(e.currentTarget).index() + 1;
$("#direct-idx").text(idx);
console.log('direct', idx);
});
$('[data-action=add-row]').click(function(e) {
var id = e.target.dataset.table;
$('#' + id + ' tbody')
.append($('<tr><td>extra</td><td>extra</td><td>extra</td></tr>')[0])
});
tr:hover{
background:#ddd;
}
button.add-row {
margin-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<h1>Event handling test</h1>
<p>Add rows to both tables and see the difference in handling.</p>
<p>Event delegation attaches a single event listener and events related to newly added children are caught.</p>
<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>
<h2>Delegation</h2>
<p><span>row index: </span><span id="delegation-idx">unknown</span></p>
<button class="add-row" data-action="add-row" data-table="table-delegate">Add row to delegation</button>
<table id="table-delegate" class="table">
<tbody>
<tr>
<td>normal</td>
<td>normal</td>
<td>normal</td>
</tr>
<tr>
<td><p>nested</p></td>
<td><p>nested</p></td>
<td><p>nested</p></td>
</tr>
<tr>
<td>normal</td>
<td>normal</td>
<td><p>nested</p></td>
</tr>
</table>
<h2>Direct attachment</h2>
<p><span>row index: </span><span id="direct-idx">unknown</span></p>
<button class="add-row" data-action="add-row" data-table="table-direct">Add row to direct</button>
<table id="table-direct" class="table">
<tbody>
<tr>
<td>normal</td>
<td>normal</td>
<td>normal</td>
</tr>
<tr>
<td><p>nested</p></td>
<td><p>nested</p></td>
<td><p>nested</p></td>
</tr>
<tr>
<td>normal</td>
<td>normal</td>
<td><p>nested</p></td>
</tr>
</tbody>
</table>
jsFiddleのデモ です。
追伸:
ネストしたテーブルがある場合(または、一般的な場合、特定の深さの要素に委任したい場合)、 jQueryバグレポートからのこの提案 を使用できます。
0から始まるインデックスを持つobject.rowIndex
プロパティを使用できます。
$("table tr").click(function(){
alert (this.rowIndex);
});
working demo をご覧ください
シンプルでjQueryのないソリューション:
document.querySelector('#elitable').onclick = function(ev) {
// ev.target <== td element
// ev.target.parentElement <== tr
var index = ev.target.parentElement.rowIndex;
}
ボーナス:行が動的に追加/削除されても動作します
$('tr').click(function(){
alert( $('tr').index(this) );
});
最初のtr
については、0をアラートします。1をアラートする場合は、インデックスに1を追加できます。
場合によっては、いくつかのテーブルを作成できますが、特定のテーブルのクリックのみを検出する必要があります。私の解決策はこれです:
<table id="elitable" border="1" cellspacing="0" width="100%">
<tr>
<td>100</td><td>AAA</td><td>aaa</td>
</tr>
<tr>
<td>200</td><td>BBB</td><td>bbb</td>
</tr>
<tr>
<td>300</td><td>CCC</td><td>ccc</td>
</tr>
</table>
<script>
$(function(){
$("#elitable tr").click(function(){
alert (this.rowIndex);
});
});
</script>