I have the standard DataTable code which populates the datatable and shows child rows on row clicks.
Inside the child row (using the format function) i have added a button and i want to do something when it's clicked but each time i click the button(data table contains child row inside a new tr->td) the event of td click which is used to open/close child rows is fired and i get "Uncaught TypeError: Cannot read property '0' of undefined"
for the d[]
array in format function.
This is the code for the child rows open/close:
$('tbody').on('click', 'td', function() {
var tr = $(this).closest('tr');
id = $(this).closest('table').attr('id');
table = $('#' + id).DataTable();
var row = table.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
} else {
// Open this row
row.child(format(row.data(), id)).show();
tr.addClass('shown');
}
});
function format(d, id) {
// `d` is the original data object for the row
if(sessionStorage['name']!=undefined)
return '<img src="images/photo.jpg" id="photo" />' + '<p>Session created by:' + d[0] + '</p>' + '<p>Start Date:' + d.start_date + '</p>' + '<p>Extra info:' + d[3] + '</p>' + "<button class='btn btn-default' id='joinbutton' role='button'>Join Session</button>";
else
return '<div>' + '<img src="images/photo.jpg" id="photo" />' + '<p>Session created by:' + d[0] + '</p>' + '<p>Start Date:' + d.start_date + '</p>' + '<p>Extra info:' + d[3] + '</p>' + '</div>';
}
Is there a way to either prevent the td click
event from being fired for child rows or to detect the button click somehow?
Thanks
I have the standard DataTable code which populates the datatable and shows child rows on row clicks.
Inside the child row (using the format function) i have added a button and i want to do something when it's clicked but each time i click the button(data table contains child row inside a new tr->td) the event of td click which is used to open/close child rows is fired and i get "Uncaught TypeError: Cannot read property '0' of undefined"
for the d[]
array in format function.
This is the code for the child rows open/close:
$('tbody').on('click', 'td', function() {
var tr = $(this).closest('tr');
id = $(this).closest('table').attr('id');
table = $('#' + id).DataTable();
var row = table.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
} else {
// Open this row
row.child(format(row.data(), id)).show();
tr.addClass('shown');
}
});
function format(d, id) {
// `d` is the original data object for the row
if(sessionStorage['name']!=undefined)
return '<img src="images/photo.jpg" id="photo" />' + '<p>Session created by:' + d[0] + '</p>' + '<p>Start Date:' + d.start_date + '</p>' + '<p>Extra info:' + d[3] + '</p>' + "<button class='btn btn-default' id='joinbutton' role='button'>Join Session</button>";
else
return '<div>' + '<img src="images/photo.jpg" id="photo" />' + '<p>Session created by:' + d[0] + '</p>' + '<p>Start Date:' + d.start_date + '</p>' + '<p>Extra info:' + d[3] + '</p>' + '</div>';
}
Is there a way to either prevent the td click
event from being fired for child rows or to detect the button click somehow?
Thanks
- 1 you may add the event to your function $('tbody').on('click', 'td', function(e) { so that you may test for e.target element, if it is not the right one you may stop your function, or you may handle the event stoppropagation – gaetanoM Commented Feb 13, 2016 at 11:37
- Being too plex to make both functions inside the same function i exctracted the button to the table into a td. thanks for the help i may e back to your answer later on – yishai Commented Feb 13, 2016 at 14:23
- Can you please provide plete example like using JSFiddle, which will be easier to understand the exact problem. Meanwhile you can try adding event.stopPropagation(); inside button click event. – Nitin Garg Commented Feb 13, 2016 at 14:58
3 Answers
Reset to default 6I propose the snippet following my remark (see the ments, not those in the format function, they are required for me to make the snippet running):
function format(d, id) {
// `d` is the original data object for the row
//if(sessionStorage['name']!=undefined)
return '<img src="http://icons.iconarchive./icons/treetog/junior/256/image-format-jpg-icon.png" id="photo" />' + '<p>Session created by:' + d[0] + '</p>' + '<p>Start Date:' + d.start_date + '</p>' + '<p>Extra info:' + d[3] + '</p>' + "<button class='btn btn-default' id='joinbutton' role='button'>Join Session</button>";
//else
//return '<div>' + '<img src="images/photo.jpg" id="photo" />' + '<p>Session created by:' + d[0] + '</p>' + '<p>Start Date:' + d.start_date + '</p>' + '<p>Extra info:' + d[3] + '</p>' + '</div>';
}
// to handle the joinbutton created dynamically you need:
// avoid to use the same ID for more than one element
$(document).on('click', 'button[role="button"]', function(e) {
alert('This is the button');
});
$(function () {
$('tbody').on('click', 'td', function(e) {
// to avoid to receive the button click inside the td you need:
if ($(e.target).is(':not(td)')) {
alert('This is inside td');
return;
}
var tr = $(this).closest('tr');
id = $(this).closest('table').attr('id');
table = $('#' + id).DataTable();
var row = table.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
} else {
// Open this row
row.child(format(row.data(), id)).show();
tr.addClass('shown');
}
});
});
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
th, td {
padding: 10px;
}
<link href="http://code.jquery./ui/1.11.3/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="http://code.jquery./jquery-1.11.3.min.js"></script>
<script src="http://code.jquery./ui/1.11.3/jquery-ui.js"></script>
<link href="//cdn.datatables/1.10.11/css/jquery.dataTables.min.css" rel="stylesheet">
<script src="//cdn.datatables/1.10.11/js/jquery.dataTables.min.js"></script>
<table id="tblId">
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<tfoot>
<tr>
<td>Sum</td>
<td>$180</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<td>February</td>
<td>$80</td>
</tr>
</tbody>
</table>
I resolve my problem with @gaemaf solution:
// Handle click on checkbox
$("#example tbody").on("click", 'input[type="checkbox"]', function(e){
var $row = $(this).closest("tr");
if(this.checked){
$row.addClass("active");
} else {
$row.removeClass("active");
}
// Prevent click event from propagating to parent
e.stopPropagation();
});
// Handle click on table cells
$("#example tbody").on("click", "td", function(e){
// Begin Solution
if ($(e.target).is(':not(td)')) {
return;
}
// End solution
$(this).parent().find('input[type="checkbox"]').trigger("click");
});
SOLUTION
Add click handler to the button and return false
from the handler to prevent default action and stop the event from propagating to parent element. Alternatively you may call stopPropagation()
and preventDefault()
.
$('#example tbody').on('click', 'button', function (e) {
// ... skipped ...
return false;
});
It would be better to remove id='joinbutton'
and use class name instead, for example btn-join
. Then you would be able to target specific button with the code below.
$('#example tbody').on('click', '.btn-join', function (e) {
// ... skipped ...
return false;
});
DEMO
See this jsFiddle for code and demonstration.