I'm using DataTables.js in my ASP.NET Core project to display a list of machines and allow users to filter the data. Each row has a button that, when clicked, toggles the display of additional details in a box below the row. Everything works fine initially, but after applying a filter, the buttons no longer work.
I've simplified the code to focus on the issue:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.5/css/jquery.dataTables.min.css">
<style>
.table-flexible th, .table-flexible td {
text-align: center;
vertical-align: middle;
padding: 8px 16px;
}
.btn {
font-size: 17px;
padding: 2px;
}
.details-row {
display: none;
}
.details-box {
padding: 10px;
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="form-group">
<label for="machineFilter">Filter by Machine:</label>
<select id="machineFilter" class="form-control" style="width: 20%; font-weight: normal">
<option value="">All Machines</option>
<!-- Example static options -->
<option value="Machine1">Machine1</option>
<option value="Machine2">Machine2</option>
</select>
</div>
<table class="table table-striped table-flexible">
<thead>
<tr>
<th>Machine</th>
<th>Description</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td>Machine1</td>
<td>Details about Machine1</td>
<td><button class="btn btn-info toggle-btn" data-target="#details1">Details</button></td>
</tr>
<tr id="details1" class="details-row">
<td colspan="3">
<div class="details-box">
Detailed information about Machine1.
</div>
</td>
</tr>
<tr>
<td>Machine2</td>
<td>Details about Machine2</td>
<td><button class="btn btn-info toggle-btn" data-target="#details2">Details</button></td>
</tr>
<tr id="details2" class="details-row">
<td colspan="3">
<div class="details-box">
Detailed information about Machine2.
</div>
</td>
</tr>
</tbody>
</table>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.datatables.net/1.10.5/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function() {
// Initialize DataTable
var table = $('.table-flexible').DataTable({
columnDefs: [{
"defaultContent": "-",
"targets": "_all"
}],
paging: false,
ordering: false,
info: false,
dom: 'ft'
});
// Custom filter for Machine
$('#machineFilter').on('change', function () {
var selectedMachine = $(this).val();
if (selectedMachine) {
table.column(0).search('^' + selectedMachine + '$', true, false).draw();
} else {
table.column(0).search('').draw();
}
});
// Attach event listener to buttons after filtering
table.on('draw', function() {
attachToggleEventListeners();
});
attachToggleEventListeners(); // Initial attachment of event listeners
function attachToggleEventListeners() {
$('.toggle-btn').off('click').on('click', function() {
var target = $(this).data('target');
$(target).fadeToggle(500); // Toggle the visibility of the target row
});
}
});
</script>
</body>
</html>
The buttons work perfectly before any filtering is applied. However, after applying a filter using the dropdown, the buttons stop working (i.e., they no longer toggle the visibility of the detail boxes).
How can I ensure that the buttons maintain their functionality even after filtering the DataTable?
Any help or examples is greatly appreciated! Thanks for your time and attention!
UPDATE: The solution provided by Jerdine Sabio works for the code I shared above, but that code does not accurately reflect what I have in my actual project. Here is a further simplification of my real code, which I ran in a .NET project.
@{
// Sample machine names
var MachineNames = new List<string> { "Machine A", "Machine B", "Machine C" };
// Sample requests using anonymous objects
var requests = new[]
{
new { Id = 1, ContactName = "Client A", CompanyName = "Machine A", Status = "Pending", Msg = "Request 1" },
new { Id = 2, ContactName = "Client B", CompanyName = "Machine B", Status = "In Progress", Msg = "Request 2" },
new { Id = 3, ContactName = "Client C", CompanyName = "Machine C", Status = "Completed", Msg = "Request 3" }
};
}
<div class="form-group">
<label for="machineFilter">Filter by Machine:</label>
<select id="machineFilter" class="form-control" style="width: 20%; font-weight: normal">
<option value="">All Machines</option>
@foreach (var machine in MachineNames)
{
<option value="@machine">@machine</option>
}
</select>
</div>
<table class="table table-striped table-flexible">
<thead class="thead-custom">
<tr>
<th>Client</th>
<th>Machine</th>
<th>Status</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var request in requests)
{
<tr>
<td>@request.ContactName</td>
<td>@request.CompanyName</td>
<td>@request.Status</td>
<td>@request.Msg</td>
<td>
<button class="btn btn-info btn-sm toggle-btn" data-target="#[email protected]">
Details
</button>
</td>
</tr>
<tr id="[email protected]" class="details-row" style="display: none;">
<td colspan="5">
<div class="card details-card">
<button class="btn btn-success btn-sm mark-seen-btn" data-id="@request.Id">Mark as Seen</button>
</div>
</td>
</tr>
}
</tbody>
</table>
@section Scripts
{
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.datatables.net/1.10.5/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function() {
var table = $('.table-flexible').DataTable({
columnDefs: [{
"defaultContent": "-",
"targets": "_all"
}],
paging: false,
ordering: false,
info: false,
dom: 'ft'
});
// Custom filter for Machine
$('#machineFilter').on('change', function () {
var selectedMachine = $(this).val();
if (selectedMachine) {
table.column(1).search( selectedMachine, true, false).draw();
} else {
table.column(1).search('').draw();
}
});
// Attach event listeners
function attachEventListeners() {
$('.toggle-btn').off('click').on('click', function() {
var target = $(this).data('target');
$(target).fadeToggle(500);
});
$('.mark-seen-btn').off('click').on('click', function() {
var id = $(this).data('id');
alert('Marked as seen: ' + id);
});
}
// Reattach event listeners after each table draw
table.on('draw', function() {
attachEventListeners();
});
// Initial attachment of event listeners
attachEventListeners();
});
</script>
}
Here's a fiddle with your updated code; https://dotnetfiddle.net/UlNwXV
$('#machineFilter').on('change', function () {
var selectedMachine = $(this).val();
if (selectedMachine) {
$.fn.dataTable.ext.search.push(
function( settings, searchData, index) {
// get filter value
var filter = $('#machineFilter').val();
// get row object from data table
var getRow = table.row(index).node();
// select row in jquery
var row = $(getRow);
// get the value from data-id
var getDataId = row.find('td[data-id]').data('id');
// if data-id == filter value, display this row
return getDataId == filter;
});
table.draw();
} else {
table.column(1).search('').draw();
}
});
data-id
to your td element, I used request.CompanyName
since it has the Machine names.@foreach (var request in requests)
{
<tr>
<td>@request.ContactName</td>
<td data-id="@request.CompanyName">@request.CompanyName</td>
<td>@request.Status</td>
<td>@request.Msg</td>
<td>
<button class="btn btn-info btn-sm toggle-btn" data-target="#[email protected]">
Details
</button>
</td>
</tr>
<tr id="[email protected]" class="details-row" style="display: none;">
<td colspan="5" data-id="@request.CompanyName">
<div class="card details-card">
<button class="btn btn-success btn-sm mark-seen-btn" data-id="@request.Id">Mark as Seen</button>
</div>
</td>
</tr>
}