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.

Recommended For You

Books

Online Courses

You Might Also Like

Comments

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)