DataTables.js过滤后按钮失效:如何维持事件监听?
问题:DataTables过滤后切换详情的按钮失效
我在ASP.NET Core项目里用DataTables.js展示机器列表,支持数据过滤,每行的按钮可以切换下方详情框的显示。初始状态下功能正常,但过滤之后按钮就失效了。
简化示例代码
<!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>
按钮在过滤前完全可用,但用下拉框过滤后,按钮没法再切换详情框的可见性。怎么确保DataTables过滤后按钮还能正常工作?
更新说明
之前的解决方案适用于上面的示例代码,但示例没准确反映我的实际项目。以下是我.NET项目里的真实代码简化版:
@{ // 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="#detailsCollapse_@request.Id"> Details </button> </td> </tr> <tr id="detailsCollapse_@request.Id" 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> }
解决方案
问题核心是:DataTables过滤时会重新渲染DOM元素,原有直接绑定的事件会丢失;同时你的详情行未被DataTables识别为关联行,过滤后可能脱离DOM或无法被正确匹配。
修复代码(针对真实项目)
替换原有脚本部分即可:
@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', // 配置DataTables识别详情行为数据行的子行 createdRow: function(row, data, dataIndex) { var nextRow = $(row).next(); if (nextRow.hasClass('details-row')) { table.row(row).child(nextRow).show(); nextRow.hide(); } } }); // 机器过滤逻辑 $('#machineFilter').on('change', function () { var selectedMachine = $(this).val(); if (selectedMachine) { table.column(1).search(selectedMachine, true, false).draw(); } else { table.column(1).search('').draw(); } }); // 用事件委托绑定按钮事件,无需重复绑定 $('.table-flexible').on('click', '.toggle-btn', function() { var target = $(this).data('target'); $(target).fadeToggle(500); }); $('.table-flexible').on('click', '.mark-seen-btn', function() { var id = $(this).data('id'); alert('Marked as seen: ' + id); }); }); </script> }
关键改进点
- 事件委托:将事件绑定到表格容器上,利用事件冒泡处理动态生成的按钮,避免每次渲染后重复绑定事件。
- DataTables子行配置:通过
createdRow回调把详情行关联到对应的数据行,确保过滤时详情行和数据行同步显示/隐藏。
修改后,无论过滤多少次,按钮功能都能正常生效。
内容的提问来源于stack exchange,提问作者Duarte Neves
相关产品推荐
相关产品推荐

