jQuery DataTables: Row selection using checkboxes

Update
January 15, 2016
See jQuery DataTables Checkboxes plug-in that makes it much easier to add checkboxes and multiple row selection to a table powered by jQuery DataTables. It works in client-side and server-side processing modes, supports alternative styling and other extensions.

This is a follow-up article to jQuery DataTables – How to add a checkbox column describing a simple solution to add checkboxes to a table. However proposed solution worked for a table using client-side processing mode only. This article offers universal solution that would work both in client-side and server-side processing modes.

It is loosely based on DataTables example – Row selection but adds extra functionality such as ability to use checkboxes for row selection and other minor improvements.

Example

Example below shows a data table using client-side processing mode where data is received from the server using Ajax. However the same code could be used if data table is switched into server-side processing mode with 'serverSide': true initialization option.

Name Position Office Extn. Start date Salary
Name Position Office Extn. Start date Salary

Data submitted to the server:


//
// Updates "Select all" control in a data table
//
function updateDataTableSelectAllCtrl(table){
   var $table             = table.table().node();
   var $chkbox_all        = $('tbody input[type="checkbox"]', $table);
   var $chkbox_checked    = $('tbody input[type="checkbox"]:checked', $table);
   var chkbox_select_all  = $('thead input[name="select_all"]', $table).get(0);

   // If none of the checkboxes are checked
   if($chkbox_checked.length === 0){
      chkbox_select_all.checked = false;
      if('indeterminate' in chkbox_select_all){
         chkbox_select_all.indeterminate = false;
      }

   // If all of the checkboxes are checked
   } else if ($chkbox_checked.length === $chkbox_all.length){
      chkbox_select_all.checked = true;
      if('indeterminate' in chkbox_select_all){
         chkbox_select_all.indeterminate = false;
      }

   // If some of the checkboxes are checked
   } else {
      chkbox_select_all.checked = true;
      if('indeterminate' in chkbox_select_all){
         chkbox_select_all.indeterminate = true;
      }
   }
}

$(document).ready(function (){
   // Array holding selected row IDs
   var rows_selected = [];
   var table = $('#example').DataTable({
      'ajax': {
         'url': '/lab/articles/jquery-datatables-checkboxes/ids-arrays.txt' 
      },
      'columnDefs': [{
         'targets': 0,
         'searchable': false,
         'orderable': false,
         'width': '1%',
         'className': 'dt-body-center',
         'render': function (data, type, full, meta){
             return '<input type="checkbox">';
         }
      }],
      'order': [[1, 'asc']],
      'rowCallback': function(row, data, dataIndex){
         // Get row ID
         var rowId = data[0];

         // If row ID is in the list of selected row IDs
         if($.inArray(rowId, rows_selected) !== -1){
            $(row).find('input[type="checkbox"]').prop('checked', true);
            $(row).addClass('selected');
         }
      }
   });

   // Handle click on checkbox
   $('#example tbody').on('click', 'input[type="checkbox"]', function(e){
      var $row = $(this).closest('tr');

      // Get row data
      var data = table.row($row).data();

      // Get row ID
      var rowId = data[0];

      // Determine whether row ID is in the list of selected row IDs 
      var index = $.inArray(rowId, rows_selected);

      // If checkbox is checked and row ID is not in list of selected row IDs
      if(this.checked && index === -1){
         rows_selected.push(rowId);

      // Otherwise, if checkbox is not checked and row ID is in list of selected row IDs
      } else if (!this.checked && index !== -1){
         rows_selected.splice(index, 1);
      }

      if(this.checked){
         $row.addClass('selected');
      } else {
         $row.removeClass('selected');
      }

      // Update state of "Select all" control
      updateDataTableSelectAllCtrl(table);

      // Prevent click event from propagating to parent
      e.stopPropagation();
   });

   // Handle click on table cells with checkboxes
   $('#example').on('click', 'tbody td, thead th:first-child', function(e){
      $(this).parent().find('input[type="checkbox"]').trigger('click');
   });

   // Handle click on "Select all" control
   $('thead input[name="select_all"]', table.table().container()).on('click', function(e){
      if(this.checked){
         $('#example tbody input[type="checkbox"]:not(:checked)').trigger('click');
      } else {
         $('#example tbody input[type="checkbox"]:checked').trigger('click');
      }

      // Prevent click event from propagating to parent
      e.stopPropagation();
   });

   // Handle table draw event
   table.on('draw', function(){
      // Update state of "Select all" control
      updateDataTableSelectAllCtrl(table);
   });

   // Handle form submission event 
   $('#frm-example').on('submit', function(e){
      var form = this;
      
      // Iterate over all selected checkboxes
      $.each(rows_selected, function(index, rowId){
         // Create a hidden element 
         $(form).append(
             $('<input>')
                .attr('type', 'hidden')
                .attr('name', 'id[]')
                .val(rowId)
         );
      });
   });

});

In addition to the above code, the following Javascript library files are loaded for use in this example:

//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js
//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js
table.dataTable.select tbody tr,
table.dataTable thead th:first-child {
  cursor: pointer;
}

The following CSS library files are loaded for use in this example to provide the styling of the table:

//cdn.datatables.net/1.10.7/css/jquery.dataTables.min.css

Edit on jsFiddle

Other examples

Problem

The problem with handling checkboxes varies based on DataTables initialization settings. In server-side processing mode ('serverSide':true) elements <input type="checkbox"> would exist for current page only. Once page is changed, the checked state of the checkboxes would not be preserved. In client-side processing mode, the checked state of checkbox is preserved, but only current page is accessible in DOM, all other pages has to be accessible through DataTables API.

Solution

The solution is to create a global variable (rows_selected in our example) to store a list of selected row IDs and use it to display checkbox state and highlight selected rows.

Highlights

Javascript

  • Storing selected row IDs

       // Array holding selected row IDs
       var rows_selected = [];

    Define array holding selected row IDs.

  • Columns definition

          'columnDefs': [{
             'targets': 0,
             'searchable': false,
             'orderable': false,
             'width': '1%',
             'className': 'dt-body-center',
             'render': function (data, type, full, meta){
                 return '<input type="checkbox">';
             }
          }],
    

    Option columnsDef is used to define appearance and behavior of the first column ('targets': 0).

    Searching and ordering of the column is not needed so this functionality is disabled with searchable and orderable options.

    To center checkbox in the cell, internal DataTables CSS class dt-body-center is used.

    Option render is used to prepare the checkbox control for being displayed in each cell of the first column.

  • Initial sorting order

          'order': [[1, 'asc']],
    

    By default, DataTables sorts table by first column in ascending order. By using order option we select another column to perform initial sort.

  • Row draw callback

          'rowCallback': function(row, data, dataIndex){
             // Get row ID
             var rowId = data[0];
    
             // If row ID is in the list of selected row IDs
             if($.inArray(rowId, rows_selected) !== -1){
                $(row).find('input[type="checkbox"]').prop('checked', true);
                $(row).addClass('selected');
             }
    

    Callback function rowCallback will be called before each row draw and is useful to indicate the state of the checkbox and row selection. We use internal DataTables CSS class selected.

    Important

    Please note that in the example above row ID is stored as first element of the row data array and is being retrieved by using the following code.

             // Get row ID
             var rowId = data[0];

    If you’re using data structure other than described in the article, adjust this and other similar lines accordingly.

  • Form submission

       // Handle form submission event 
       $('#frm-example').on('submit', function(e){
          var form = this;
          
          // Iterate over all selected checkboxes
          $.each(rows_selected, function(index, rowId){
             // Create a hidden element 
             $(form).append(
                 $('<input>')
                    .attr('type', 'hidden')
                    .attr('name', 'id[]')
                    .val(rowId)
             );
          });
       });
    

    When table is enhanced by jQuery DataTables plug-in, only visible elements exist in DOM. That is why by default form submits checkboxes from current page only.

    To submit selected checkboxes from all pages we need to iterate over rows_selected array and add a hidden <input> element to the form with some name (id[] in our example) and row ID as a value. This will allow all the data to be submitted.

    For more information on submitting the form elements in a table powered by jQuery DataTables, please see jQuery DataTables: How to submit all pages form data.

HTML

<table id="example" class="display select" cellspacing="0" width="100%">

Additional CSS class select is used to change cursor when hovering over table rows for specific tables only.

CSS

table.dataTable.select tbody tr,
table.dataTable thead th:first-child {
  cursor: pointer;
}

Display cursor in the form of a hand for table rows and first cell in the table heading where “Select all” control is located.

You Might Also Like

Comments

  1. Hey,

    I have an issue I can’t resolve:
    When I check a box and I change page using pagination, all the checkboxes on the next page are checked.

    I especially created a directory and added your code into a new file that I called index.html with needed links of js and css, still the bug remain.

    The only thing I change is the Ajax part, instead of using this :

          'ajax': {
             'url': '/lab/articles/jquery-datatables-checkboxes/ids-arrays.txt'
          },
    

    I am using this (I have a var called dataSet with an initialized list, it is working correctly):

       data: dataSet,
    
        1. {
          “ID”:61,
          “UserName”:”LAF-000098″,
          “FullName”:”sandstruck test”,
          “Email”:”123@qwer.vbn”
          },

          var table = $(‘#example’).DataTable({
          ‘ajax’: {
          ‘url’: ‘/WLC/AdminInterfaces/ClientResources/css/ids-arrays.txt’
          },
          “columns”: [
          { data: “ID” },
          { data: “UserName” },
          { data: “FullName” },
          { data: “Email” }
          ],
          ‘columnDefs’: [{
          ‘targets’: 0,
          ‘searchable’: false,
          ‘orderable’: false,
          ‘width’: ‘1%’,
          ‘className’: ‘dt-body-center’,
          ‘render’: function (data, type, full, meta) {
          return ”;
          },

          }],
          ‘order’: [[1, ‘asc’]],
          ‘rowCallback’: function (row, data, dataIndex) {
          // Get row ID
          var rowId = data[0];

          // If row ID is in the list of selected row IDs
          if ($.inArray(rowId, rows_selected) !== -1) {
          $(row).find(‘input[type=”checkbox”]’).prop(‘checked’, true);
          $(row).addClass(‘selected’);
          }
          }
          });

    1. This may occur if your dataset doesn’t have unique values for the column containing checkboxes. Notice that Ajax response in my examples contains 1, 2, 3 as the values for the first column containing checkboxes.

      Overall I recommend to use jQuery DataTables Checkboxes plugin instead as it simple to use and supports various jQuery DataTables extensions as well.

  2. Hi,
    In this specific example for select rows using checkbox, you have handled the click event of checkbox for select the data table row. In that event, you have handled the code by adding/removing “selected” class of data table row. Is actually displayed that row is selected but it is not actually consider as selected row by data table functions.

    Proper way to select or deselect row is use the jquery Datatable function as below link.
    https://datatables.net/reference/api/row().select()
    https://datatables.net/reference/api/rows().deselect()

    So I just replaced the code for selecting/deselecting rows on the click event of checkboxes as below,

    
    $('#example tbody').on('click', 'input[type="checkbox"]', function(e){
          if(this.checked){
             $row.addClass('selected');
          } else {
             $row.removeClass('selected');
          }
    });
    
  3. Hello how can i get the id of the checkboxes , currenly using MS server databse in jquery datatable and when i hit the submit button the id comes out empty

    1. Possibly you’re not providing data initially for the column containing checkboxes. Or not retrieving the data from appropriate request parameter. It is hard to say without seeing the actual code.

    1. Dear,
      I am also waiting for the answer. I am facing so much difficulty with this in MVC ASP.Net.
      Hope someone will post complete answer. Pray to the god.

  4. What if the ajax response is array with key name? What should i change this part data[0] with? I’ve tried by change to data[‘id’], but it doesn’t work.

      1. I have another problem when i try to set initial value of checkbox. It’s checked, but when i submit the form, it’s return null

        1. Can you share the code to set the initial value of checkbox? I am trying to do the same without any lucks.
          What i was trying to accomplished was providing the user the ability to edit their data so when they load the table the second time I wanted to check the checkboxes based on their saved data.

  5. After form posted event, returned all columns checked.

    This line is causing problems during post processing.
    I found the solution to interpret it:

    if($.inArray(rowId, rows_selected) !== -1){
       /*$(row).find('input[type="checkbox"]').prop('checked', true);
       $(row).addClass('selected');*/
    }
    
  6. Heelo Mr. Michael.. I have a case in selected data for a row…for example , I can’t bring column of office or salary..how to escape it (bring into data submitted)?

  7. Can you share the codes to set the initial value of checkbox(s)?
    What i was trying to accomplished was providing the user the ability to edit their data so when they load the table the second time I wanted to check the checkboxes based on their saved data.

  8. Show/Hide rows on custom button click

    We need to create a click button to hide and show selected and unselected row only.
    For example:
    1. If click to “Check Selection” button, then show only selected rows and Unselected rows hide.
    2. If click to “Uncheck Selection” button, then show only unselected rows and selected rows hide.

  9. Hi Michael

    I’m using your jQuery DataTables Checkboxes plugin. Great work by the way. I manage to get the selected elements (unique ids in my case) like so:

    table.column(0).checkboxes.selected()

    I send those by Jquery Ajax call to an API which deletes the data in the database. On Success I want to delete the selected rows.

    I know how to delete all the rows like so:

    table.rows().remove().draw()

    Now I would like to only delete the selected rows. But everything I try doesn’t work as expected. Any help is appreciated.

      1. Thank you! I checked your fiddle. I tried your proposed solution. It didn’t work. I get this error:

        Uncaught TypeError: $(…).DataTable(…).rows(…).deselect is not a function

        Just to be sure I implemented this as well:

        
        $('#btn-remove').on('click', function(){
                        $('#scrapingUrls').DataTable().rows({ selected: true }).deselect().remove().draw();   
                    });
        

        I get, not to my surprise, the same error. Do you have an idea what I might make wrong? The checkbox and datatable plugin works fine.

  10. I have a problem. I can’t loop to get row values from datatable row when I click on submit button. For example:

    1  Jack  12  USA.
    .
    .
    .
    .
    N
    

    And I want to get value from row. But I only get: “x ros selected”. I can’t get the value from each row.

  11. how do count the number of checkboxes that are checked ?

    i would like to do a if checkbox.checked count < 1 then button is disable

Leave a Reply

You may use simple HTML to add links or lists to your comment. Also use <pre><code class="language-*">...</code></pre> to mark up code snippets. We support language-js, language-markup and language-css for comments.
(Optional)