skip to Main Content

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


  1. 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();

    <!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>
    Login or Signup to reply.
  2. Here’s a fiddle with your updated code;
    https://dotnetfiddle.net/UlNwXV

    1. Create a custom filter and use it on your on change event;
    $('#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();
       }
    });
    
    1. Add 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>                
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search