Here is my scenario:
I have a table that displays the Name, Age, and Details content on each row. When a user selects the Details button, it should trigger a modal and show additional content specific to that Person in the table.
Issue at hand:
I am using Razor syntax and dynamically generating the rows within the table.
Question: How can I get the row index value for that specific row when selecting the Details button
Additional Notes:
I did some research online, but couldn't find anything that helped me in my scenario.
Html
<div class="col-md-12">
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Details</th>
</tr>
</thead>
<tbody>
#foreach (var viewModel in Model)
{
<tr>
<td>#viewModel.Name</td>
<td>#viewModel.Age</td>
<td><button onclick="PersonViewModel(this)" type="button" class="btn btn-success" data-toggle="modal" data-target="#details-modal"><span class="fa fa-external-link-square"></span> Details</button></td>
</tr>
}
</tbody>
</table>
</div>
JavaScript:
function PersonViewModel(x) {
$('body').on('click', 'a.showMore', function(event) {
var rowIndex = $(this).closest('tr').index();
alert("Row index is: " + rowIndex);
});
}
You are binding event in the PersonViewModel click handler. In order to get the index of parent tr, you need to use the x object.
Use
function PersonViewModel(x) {
var rowIndex = $(x).closest('tr').index();
alert("Row index is: " + rowIndex);
}
You can try like this. I think this will help you.
$(this).parents('tr')).index()
This will give you parent tr and index() function will give index of that tr.
Please check my code instead of your
function PersonViewModel(x) {
var index = $(".table tr").index( $(x).parents('tr'));
alert(index);
}
Related
How do you get the id from a row element that has been dynamically created. Below is the code that I have tried but it will not fire the event.
HTML
<table id="tblRawMaterials" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th>
A
</th>
<th>
B
</th>
<th>
C
</th>
</tr>
</thead>
<tbody>
<tr id="DCB4325E-951C-67E3-1E8F-7270D488A1EB" >
<td>G20002</td>
<td>1,783</td>
<td>2,000</td>
</tr>
</tbody>
</table>
Script
$("#tblRawMaterials tbody").click( function(e) {
// Here i need to capture row id of clicked cell.
});
Thanks in advance
you need the equivalent (old) sintax of on, exactly the same concept:
$("#tblRawMaterials tbody").delegate('tr', 'click', function(e) {
console.log($(this).attr('id'))
});
You need to use event delegation, in this way the event is attached to the parent tbody and fired anytime that a tr is clicked. It doesn't depend on the tr, so it will work also for elements dynamically added.
Please check che fiddle
You can try like this also with closest
$(document).ready(function() {
$("#tblRawMaterials tbody").click(function(e) {
var $tr = $(e.target).closest('tr'),
rowId = ($tr).attr("id"); // Here you can capture the row id of clicked cell.
alert(rowId);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<table id="tblRawMaterials" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th>
A
</th>
<th>
B
</th>
<th>
C
</th>
</tr>
</thead>
<tbody>
<tr id="DCB4325E-951C-67E3-1E8F-7270D488A1EB">
<td>G20002</td>
<td>1,783</td>
<td>2,000</td>
</tr>
</tbody>
</table>
UPDATE :
If you really need delegate, then you can use the following code snippets.
$(document).ready(function () {
$(document).delegate("#tblRawMaterials tbody", "click", function (e) {
var $tr = $(e.target).closest('tr'),
rowId = ($tr).attr("id"); // Here you can capture the row id of clicked cell.
alert(rowId);
});
});
Note: Here I didn't bind click event for tr element.
Hope this helps!
You need to use event delegation, in this way the event is attached to the parent tbody and fired anytime that a tr is clicked. It doesn't depend on the tr, so it will work also for elements dynamically added.
$("#tblRawMaterials tbody").on('tr','click',function(e) {
var id = $(this).attr('id');
});
use jQuery delegate
Description: Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a
specific set of root elements.
$("#tblRawMaterials tbody").delegate('tr','click',function(e) {
var id = $(this).attr('id');
});
try this
$(document).ready(function () {
$('#tblRawMaterials tr').click(function () {
alert($(this).attr('id'));
});
});
I have a table structure like this (refer below)
<table>
<thead>
<tr><th>id</th><th>name</th><th>address</th></tr>
</thead>
<tbody>
<tr rowid="1">
<td class="columnid">1</td><td class="columnname">name 1</td><td class="columnaddress">address 1</td>
</tr>
<tr rowid="2">
<td class="columnid">2</td><td class="columnname">name 2</td><td class="columnaddress">address 2</td>
</tr>
<tr rowid="3">
<td class="columnid">3</td><td class="columnname">name 3</td><td class="columnaddress">address 3</td>
</tr>
</tbody>
</table>
Now, I want to get the content from each table row that has attr('columnid') and loop each of it. So the code structure would look like this (refer below)
//We have 3 row, get all present rowid (1,2,3)
//count all the row that has rowid attribute
var rowcount = attr('rowid').length();
var i;
for (i = 0; i < rowcount; i++) //I dont know how to make it but assume in this for statement, I have stored the content from each rowid attribute {
//alert each rowid here
}
how to make it? any help, suggestions, recommendations, ideas, clues would be greatly appreciated. Thank you.
You can use tr[rowid] which will find all tr elements with rowid attribute, then use .has() to filter out trs which do not have td with class columnid like
$('tr[rowid]').has('td.columnid').each(function(){
alert($(this).attr('rowid'))
});
Demo: Fiddle
This code will scan all the td's with class columnidand alert the rowid of the row containing it. I hope this is what you want you code to do.
$("tr td.columnid").each(function(){
alert($(this).parent().attr("rowid"));
});
Fiddle
I have the following html which is basically a parent table with some child tables inside it,
<table id="roottable" class="tablemain" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td></td>
<td>
<table class="intable" align="center" border="0">
<tbody>
<tr>
<td class="chn" colspan="2" align="center">
<div>
<div class="mparent">
<div class="checkbox">
<input type="checkbox" id="ch243" name="ch243" value="243">
<label for="ch243"></label>
</div>
<div class="chtext">Category</div>
</div>
</div>
</td>
</tr>
<tr>
<td>Param two</td>
<td>
<div class="checkbox">
<input type="checkbox" id="ch244" name="ch244" value="244">
<label for="ch244"></label>
</div>
</td>
</tr>
</tbody>
</table>
......
......
<table class="intable" align="center" border="0">
......
......
What I need to do is access all checkboxes of the nested table, for each table. That is get the checkboxes inside the first nested table, perform some operations with it, move to the next nested table do the same with the checkboxes inside it.
I can access individual tables like below with their id,
$('#tableid').find('input[type="checkbox"]').each(function () {
});
This works, but the tables are auto generated from db and the id is not known beforehand, also, the number of tables may vary, so I have no option other than selecting the parent table and then look for every child tables inside it one by one ... I have tried this ...
$('table').each(function(){
$(this).find('input[type="checkbox"]').each(function () {
// DO STUFFS WITH CHECKBOXES
});
But it doesn't work... How do I go about this? Thanks.
$('table tr td').each(function(){ // this line is for main outer table
$(this).children('table').each(function () { //this will iterate all the child table
$(this).find('input:checkbox').each(function(){ //this will find checkbox inside each table
//Your Stuff
});
});
});
NOTE :- I m not using id selector here because questioner mentioned that he doesn't know id's beforehand.
Working Demo
Working Demo
Your final code block looks acceptable, except that you haven't prevented the table selector from also selecting the outer table. As written, this would cause each set of checkboxes to be considered twice - once as part of its own table and again (actually first) as descendants of the outer table.
Try a more specific selector:
$('#roottable .intable').each(...)
I would do something like this:
$('#roottable').find('.intable').each(function(index, elt) {
// operate now on each "child table"
var $childTable = $(elt);
$childTable.find('input[type="checkbox"]').each(function(i, cb){
// Do your stuff with the checkoxes of the current ".intable" table
});
});
Just use:
var tableInputs = {};
$('#roottable input[type="checkbox"]').each(function () {
var id = $(this).closest('table').attr('id');
var name = $(this).attr('name');
tableInputs[id] = {};
tableInputs[id][name] = $(this).val();
});
This will select all checkboxes that are a child of a table.
EDIT if you need to group just find the id of the closest parent table and use that as an index for an object. You end up with one large object with all the id's as properties, while using only one each loop.
I have a table like the following
<table id="adminTable">
<thead>
<tr>
<th></th>
<th>Username</th>
<th>Email</th>
<tr>
</thead>
<tbody>
<tr><td><input type='checkbox' name='selected_users[]' value='User1'/></td><td>User1</td><td>mail1#mail.com</td></tr>
<tr><td><input type='checkbox' name='selected_users[]' value='User2'/></td><td>User2</td><td>mail2#mail.com</td></tr>
...
</tbody>
</table>
I have a button below which calls a javascript-function.
This function then should get all the emails for the users which were selected via their checkboxes...
I am quite new to Javascript and jQuery an am not sure of how to achieve this...
But I can use plain Javascript or use jQuery...
What I already found was this, but I can't get it to help me, because I don't want a button in my row (multiple selections shall be possible via the checkboxes).
You can use the following function which run on a button click:
$(":button").click(function() {
var emails = $("input[name=selected_users[]]:checked").map(function() {
return $(this).closest("td").next("td").text();
}).get();
console.log(emails); //array of emails that were checked
});
$("#adminTable").find("td").filter(function()
{
return $(this).find("input[type=checkbox]:checked").length > 0;
});
Keep in mind you have TR tags in your html that don't have closing tags and are out of place.
I have a table like the following:
<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>
When a user clicks on the table, how can I get the index of this row (tr element)?
For example, when I click on the first tr (with 1s in the above table), it should pick it up and return 1.
This would get you the index of the clicked row, starting with one:
$('#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>
If you want to return the number stored in that first cell of each row:
$('#thetable').find('tr').click( function(){
var row = $(this).find('td:first').text();
alert('You clicked ' + row);
});
A better approach would be to delegate the event, which means catching it as it bubbles to the parent node.
delegation - overview
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.
implementation
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.
example
A comparison between direct handler attachment and delegation is available below or 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>
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.
A simple and jQuery free solution:
document.querySelector('#elitable').onclick = function(ev) {
// ev.target <== td element
// ev.target.parentElement <== tr
var index = ev.target.parentElement.rowIndex;
}
Bonus: It works even if the rows are added/removed dynamically
You can use object.rowIndex property which has an index starting at 0.
$("table tr").click(function(){
alert (this.rowIndex);
});
See a working demo
$('tr').click(function(){
alert( $('tr').index(this) );
});
For first tr, it alerts 0. If you want to alert 1, you can add 1 to index.
In some cases we could have a couple of tables, and then we need to detect click just for particular table. My solution is this:
<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>
DEMO