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>
}
2
Answers
Edit: Added a new answer that searches multiple columns via data attribute.
The problem arent the buttons. If you add an alert inside that click event, the alert still shows after filtering.
The problem is with your regex, it also hides your details row, hence your click function can’t find it. Use this instead.
table.column(0).search(selectedMachine, true, false).draw();
Here’s a fiddle with your updated code;
https://dotnetfiddle.net/UlNwXV
data-id
to your td element, I usedrequest.CompanyName
since it has the Machine names.