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.
//
// 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.cssOther 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.
This is great article! Just wondering from something that I work on. How could a user select all data in the server-side example?
As I click the check all checkbox, user might expect they select all data instead all the displaying page record.
Nice article! Help me a lot. I was working with a large amount of data (more than 10 000 rows) and the method to manage the ‘Select All’ was slow because we the triggered the click event several times. My workaround was this:
Nice article. When I try, it only select check boxes on first page not on the other pages? Could you please assist me?
This is an example of poor UX. Selecting a row should not select the checkbox automatically. It is considered an unexpected behavior. What happens if you want to support multiple links on a row? Or if you want to support inline editing on a row. While the solution is attractive an elegant, it is not considered standard behavior in user experience. I’d be happy to discuss this further.
John, thank you for your detailed comment. I can partially agree with you. My example shows one particular use case. Links would need to be handled accordingly so that click on the link doesn’t select a row. In case of inline editing, row selection will be distracting, it’s true. But my article tries to solve the problem of handling checkboxes in the table powered by jQuery DataTables, row highlighting is an extra bonus and can be removed from the code with some effort.
After selecting one or more rows I needed to apply some functionality on them and this involved ajax call. After completion of ajax call JQuery fires callbacks and within these callbacks it calls a JQuery method jQuery.ajaxTransport( option ) which has a function that gets ‘type’ parameter from i don’t know where and this parameter is undefined
So after this function ALL REMAINING CHECKBOXS AND ROWS ARE SELECTED automatically and checkbox in header is selected too
Well I found the error it was because of the rowCallback method
Hi how to make this table as responsive?
Hi , Thanks for this. I tried implementing the same, but when i alert the rowid.value on onSubmit, it is working only for the page where i am in. for example if i am in first page i can get the value in alert on only that page, not the second one. Any Help ?
I have textboxes in my rows and want to get the values of text boxes when i submit, am able to get values for only the first page records, not for the second one. Similarly if i navigate to second page i am able to get the text box values for second page only not the first page.
May i know the resolution for this ?
First, thank you very much for the tutorial as it helped me a lot.
I’m having some problems which I have documented on Stackoverflow: http://stackoverflow.com/questions/41130976/submitting-form-resubmits-the-same-data
Basically I set it up to post back using ajax so I didn’t have to do a page refresh when submitting. But running into a problem where the form variable still holds on to previously selected values even though they won’t appear in the rows_selected variable.
If you have a few minutes could you take a look please?
Nevermind I figured it out. I ended up iterating back over the selected rows and removing the elements from the form variable after I get a success back from ajax.
How can I get this to work with fixedColumn, So that the checkbox column is fixed?
Please see jQuery DataTables Checkboxes which now has support for FixedColumns and FixedHeader extensions.
Hello . I have a problem. I can manage to select all the values. I have the pagination on my table and when i select all , i just get checked the fields that i have in the actual page.
After debugin i sow that in data object just have the rows in selected page, not al the pages.
Is possible … when i build the table to assign all data , not only the first page ?¿
I sow that you have a answer at this problem. But is just not working for me.
Please someone help .
How would you handle selecting all paginated records (including the pages not yet fetched) in a server side processing table?
I have a select all column checkbox for the current page that, when clicked, shows a link to select all paginated rows. I set it up that when you visit each page, the checkboxes are added to the array and set to true. It is a small quandary because It will only retain the data on the pages you visited. What about the scenario where the user modifies some checkboxes (or worse, checks the page’s select all to false) and leaves that page and comes back? You would not know the difference.
Maybe I can track what the user deselects and overlay that against the default select all. That makes more sense to me.
We’re considering adding this feature to jQuery DataTables Checkboxes plugin, please see issue #19 on GitHub.
Basically, you would need to track three things: last state of “Select all” control, list of checked checkboxes and list of unchecked checkboxes.
You need to submit all this information to the server-side script which then should be able to tell the state of all checkboxes.
Hope that makes sense.
Initially I thought I could just get away with a deselected list, but the pagination would still save the checkbox state on non-current pages after I clear all table checkboxes. So yes, your reply makes sense. It would be based on the state of the select all whether you take all records minus the unchecked list or just the checked list, if not empty.
It is not very eloquent how I wrote it using jQuery, but it gets the job done for now and it can be improved later. Thanks.
Hi my friend, I wish to adquire your wonderfull code for a personal project. Also before, I want a litte of support.
Regards
What is the price?
The plug-in is released under MIT license, you can use it for free in your personal or commercial project.
I have custom check-boxes like above and also have edit button, but clicking edit button it shows blank form as rowId is not updated.
How can we pragmatically set rowId to table? I have to set it inside checkbox checked event. Please help
Thanks for the perfect script. But what is to do when the click event should just be on the checkbox and not on one of the other elements in the data row?
Do you mean that you don’t need row selection?
it worked for me by adding a line
selector: ‘input[type=”checkbox”]’
Nice tutorial! I have Error Message “Illegal mix of collations for operation ‘like’” when search about something. My database Collation Is utf8_general_ci. How to fix that? Thanks!
Hi,
I am very happy with what you did, I managed to select rows while still keeping pagination, however, when I want to deselect all previously selected rows, it only deselects the ones on the current page, and not all the pages.
I followed these steps for the selection part : http://www.gyrocode.com/projects/jquery-datatables-checkboxes/
I tried doing “table.column(0).checkboxes.deselect();” for the deselection part, but it only works on the current page.
Can you please explain how to do it ?
Thansk a lot !!
Based on your description you probably use server-side processing mode. Currently in that mode only current page checkboxes is selected/deselected via API. Although you make a good point, I will think about possible workaround.
Thanks for your answer !
Yes indeed, server-side, and pagination, but it is working perfectly for the selection using “table.column(0).checkboxes.selected();”,
As for the options of Datatables, I have :
For the deselection it is not working however: it is only working for the displayed page
Thanks for your precious help !
Hello,
Thanks for the nice article.
I would like help here I want to send these selected data to php for further processing.
Please help am not good in coding.
Edes, examples in this, this and this articles illustrate how checkboxes data could be submitted to the server, see
submit
event handler.Please help me, I am getting this error.
Can you please send me a link to the page demonstrating the problem? Most likely the reason is that you including JS files in the wrong order. You need to include
datatables.min.js
beforedataTables.checkboxes.min.js
.Hello, I’m having some trouble I believe with the rowId
In Chrome debug I see this:
rowId = undefined, data = Object {Name: “Hugo Boss”, Job: “208-01”, Location: “003127”, TrackingNumberOut: “946039840259616 “, TrackingNumberIn: “946
the data Object is 0 index based. The number I want for the ID is Location:, I have var rowId = data[2]; set but still get this result.
Any help is appreciated.
SOLVED:
I realized that the data Object is an Object and not an array.. I can access it by rowId = data.Location;
Your article is very helpful and easy to understand thank you.