jQuery DataTable Order Table Based On Checkbox

Viewed 2610

I have a table:

<table id="Equipment-Table" class="table table-bordered table-hover">
    <thead>
        <tr>
            <th class="text-center">
                @Html.DisplayNameFor(model => model.TypeOfEquipment)
            </th>
            <th class="text-center">
                @Html.DisplayNameFor(model => model.Deleted)
            </th>
            <th></th>
        </tr>
    </thead>

    <tbody>
        @foreach (var item in Model)
        {
            <tr class="text-center">
                <td>
                    @Html.DisplayFor(modelItem => item.TypeOfEquipment)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Deleted)
                </td>
                <td>
                    @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                    @Html.ActionLink("Details", "Details", new { id = item.Id }) |
                    @Html.ActionLink("Delete", "Delete", new { id = item.Id })
                </td>
            </tr>
        }
    </tbody>
</table>

I am using jQuery DataTables to style it and give it functionality.

This produces this:

enter image description here

My goal:

Order by the Deleted column. I want deleted items to be at the bottom of the list.

Here is what I have so far:

$(document).ready(function() {
    var equipmentTable = $("#Equipment-Table").DataTable({
        "order": [1, "asc"],
        "aoColumnDefs": [
            { "bSortable": false, "aTargets": [1, 2] },
            { "bSearchable": false, "aTargets": [1, 2] }
        ]
    });
});

How can I make this happen?

Update

<tr class="text-center">
    <td>
        @Html.DisplayFor(modelItem => item.TypeOfEquipment)
    </td>
    @if (item.Deleted)
    {
        <td data-order="1">
            @Html.DisplayFor(modelItem => item.Deleted)
        </td>
    }
    else
    {
        <td data-order="0">
            @Html.DisplayFor(modelItem => item.Deleted)
        </td>
    }

    <td>
        @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
        @Html.ActionLink("Details", "Details", new { id = item.Id }) |
        @Html.ActionLink("Delete", "Delete", new { id = item.Id })
    </td>
</tr>


$(document).ready(function() {
    var equipmentTable = $("#Equipment-Table").DataTable({
        "aoColumnDefs": [
            { "bSortable": false, "aTargets": [1, 2] },
            { "bSearchable": false, "aTargets": [1, 2] }
        ]
    });

    $('#Equipment-Table input[type="checkbox"]').on('change', function () {
        // Update data-sort on closest <td>
        $(this).closest('td').attr('data-order', this.checked ? 1 : 0);

        // Store row reference so we can reset its data
        var $tr = $(this).closest('tr');

        // Force resorting
        equipmentTable
          .row($tr)
          .invalidate()
          .order([1, 'asc'])
          .draw();
    });
});
1 Answers

You are using the legacy DataTables API: you should avoid using that, because it is being replaced by a more verbose and readable one.

You can sort your checkbox column programatically by using a combination of the following strategy:

  • When the page is first rendered, set the data-sort / data-order attribute to reflect the (un)checked status. In the example below, I settled for 0 for unchecked and 1 for checked. This should be handled by your templating/layout logic.

    <!-- Rendered markup for UNCHECKED -->
    <td data-order="0"><input type="checkbox" /></td>
    
    <!-- Rendered markup for CHECKED -->
    <td data-order="1"><input type="checkbox" checked /></td>
    
  • We bind a click event handler to the checkbox input. When the onChange event is fired, we simply:

    1. Dynamically update the data-sort/data-order attribute based on the checked status of the checkbox
    2. Invalidate the cached data stored for the row (so DataTables will have to reindex the data-sort/data-order attribute), using .row().invalidate()
    3. Resort the table using .sort()
    4. Trigger redrawing using .draw(), as the step above does not reflow/redraw the table

Here is a proof-of-concept example:

$(document).ready(function() {
  var equipmentTable = $("#Equipment-Table").DataTable({
    "order": [1, "asc"]
  });

  // Listen to change event from checkbox to trigger re-sorting
  $('#Equipment-Table input[type="checkbox"]').on('change', function() {
    // Update data-sort on closest <td>
    $(this).closest('td').attr('data-order', this.checked ? 1 : 0);
    
    // Store row reference so we can reset its data
    var $tr = $(this).closest('tr');
    
    // Force resorting
    equipmentTable
      .row($tr)
      .invalidate()
      .order([ 1, 'asc' ])
      .draw();
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.16/js/jquery.dataTables.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet" />

<table id="Equipment-Table" class="table table-bordered table-hover">
  <thead>
    <tr>
      <th class="text-center">
        Type of Eqiupment
      </th>
      <th class="text-center">
        Deleted
      </th>
      <th></th>
    </tr>
  </thead>

  <tbody>
    <tr class="text-center">
      <td>Lorem</td>
      <td data-order="0"><input type="checkbox" /></td>
      <td>...</td>
    </tr>
    <tr class="text-center">
      <td>Ipsum</td>
      <td data-order="0"><input type="checkbox" /></td>
      <td>...</td>
    </tr>
    <tr class="text-center">
      <td>Dolor</td>
      <td data-order="1"><input type="checkbox" checked /></td>
      <td>...</td>
    </tr>
    <tr class="text-center">
      <td>Sit</td>
      <td data-order="1"><input type="checkbox" checked /></td>
      <td>...</td>
    </tr>
    <tr class="text-center">
      <td>Amet</td>
      <td data-order="0"><input type="checkbox" /></td>
      <td>...</td>
    </tr>
  </tbody>
</table>

Update

It seems like OP is only interested in enforcing initial sorting of the table, while disabling user-initiated sorting and search. The checkboxes are also disabled by default, which means we do not need to bind event listeners to them since we do not expect the user to toggle this option. This can be done with the following config:

{
  "order": [1, "asc"],
  "columnDefs": [
    { "orderable": false, "targets": [0,1,2] },
  ],
  "searching": false
}

Proof-of-concept:

$(document).ready(function() {
  var equipmentTable = $("#Equipment-Table").DataTable({
    "order": [1, "asc"],
    "columnDefs": [{
      "orderable": false,
      "targets": [0, 1, 2]
    }],
    "searching": false
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.16/js/jquery.dataTables.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet" />

<table id="Equipment-Table" class="table table-bordered table-hover">
  <thead>
    <tr>
      <th class="text-center">
        Type of Eqiupment
      </th>
      <th class="text-center">
        Deleted
      </th>
      <th></th>
    </tr>
  </thead>

  <tbody>
    <tr class="text-center">
      <td>Lorem</td>
      <td data-order="0"><input type="checkbox" disabled /></td>
      <td>...</td>
    </tr>
    <tr class="text-center">
      <td>Ipsum</td>
      <td data-order="0"><input type="checkbox" disabled /></td>
      <td>...</td>
    </tr>
    <tr class="text-center">
      <td>Dolor</td>
      <td data-order="1"><input type="checkbox" checked disabled /></td>
      <td>...</td>
    </tr>
    <tr class="text-center">
      <td>Sit</td>
      <td data-order="1"><input type="checkbox" checked disabled /></td>
      <td>...</td>
    </tr>
    <tr class="text-center">
      <td>Amet</td>
      <td data-order="0"><input type="checkbox" disabled /></td>
      <td>...</td>
    </tr>
  </tbody>
</table>

Related