J'ai une table comme celle-ci:
<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>
Lorsqu'un utilisateur clique sur la table, comment puis-je obtenir l'index de cette ligne (élément tr
?)?
Par exemple, lorsque je clique sur le premier tr
(avec 1
s dans le tableau ci-dessus), il devrait le ramasser et renvoyer 1
.
Cela vous donnerait l'index de la ligne cliquée, en commençant par un:
$('#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>
Si vous souhaitez renvoyer le numéro stocké dans cette première cellule de chaque ligne:
$('#thetable').find('tr').click( function(){
var row = $(this).find('td:first').text();
alert('You clicked ' + row);
});
Une meilleure approche consisterait à déléguer l’événement, c’est-à-dire l’attraper au moment où il émet des bulles au nœud parent.
Cette solution est à la fois plus robuste et efficace.
Il permet de gérer l’événement même si plusieurs lignes sont ajoutées dynamiquement à la table ultérieurement. Cela implique également de lier un seul gestionnaire d’événements au nœud parent (table
élément), au lieu d’une pour chaque nœud enfant ( tr
element).
En supposant que l'exemple du PO soit simplifié, la structure de la table peut être plus complexe, par exemple:
<table id="indexedTable">
...
<tr>
<td><p>1</p></td>
<td>2</td>
<td><p>3</p></td>
</tr>
</table>
Par conséquent, une approche simpliste telle que l’obtention de e.target.parentElement
Ne fonctionnera pas, car cliquer sur le bouton interne <p>
Et cliquer sur le centre <td>
Produira des résultats différents.
L'utilisation de la délégation normalise la gestion des événements, en supposant seulement qu'il n'y a pas de tables imbriquées.
Les deux extraits suivants sont équivalents:
$("#indexedTable").delegate("tr", "click", function(e) {
console.log($(e.currentTarget).index() + 1);
});
$("#indexedTable").on("click", "tr", function(e) {
console.log($(e.currentTarget).index() + 1);
});
Ils attachent un écouteur à l'élément table
et gèrent tous les événements provoquant des bulles dans les lignes du tableau. L'API actuelle est la méthode on
et la méthode delegate
est une API héritée (et appelle en réalité on
en coulisse).
Notez que l'ordre des paramètres des deux fonctions est différent.
Une comparaison entre l'attachement direct du gestionnaire et la délégation est disponible ci-dessous ou sur 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>
Voici le démo sur jsFiddle .
P.S:
Si vous avez des tables imbriquées (ou, dans le cas général, souhaitez déléguer des éléments d'une profondeur spécifique), vous pouvez utiliser cette suggestion du rapport de bogue jQuery .
Vous pouvez utiliser object.rowIndex
propriété qui a un index commençant à 0.
$("table tr").click(function(){
alert (this.rowIndex);
});
Voir une démonstration de travail
Une solution simple et sans jQuery:
document.querySelector('#elitable').onclick = function(ev) {
// ev.target <== td element
// ev.target.parentElement <== tr
var index = ev.target.parentElement.rowIndex;
}
Bonus: Cela fonctionne même si les lignes sont ajoutées/supprimées dynamiquement
$('tr').click(function(){
alert( $('tr').index(this) );
});
Pour la première tr
, il alerte 0. Si vous souhaitez alerter 1, vous pouvez ajouter 1 à l'index.
Dans certains cas, nous pourrions avoir deux tables, puis nous devions détecter les clics uniquement pour une table en particulier. Ma solution est la suivante:
<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>