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, but How can I sum the Salary column select on the radio button?
See Footer callback example that shows how to do summarize data in the table.
How can I select all records from the beginning?
With the current code the easiest way would be to use the code below:
See this jsFiddle for demonstration.
How to do I select only specific records where IDs had been saved before?
As I mentioned before, retrieve IDs and populate
rows_selected
array.What if the checkbox is generated by js cause they have data info prop and no id for limit repeating them. I want to know how to send only the selected rows to another datatable. I’m only able to pass all data rows from one to another. Thanks in advance.
Thank you for posting this! It really helps. I had one question I’ve been beating my head again for a while. Is there a way to add column filtering? I’ve attempted to add this link below but haven’t had much success. http://datatables.net/examples/api/multi_filter.html Thank you!
Sure, you can implement it yourself as described in the link you’ve posted. There is also YADCF (yadcf-showcase.appspot.com) plug-in for jQuery DataTables.
Thank you Michael, I learned a lot from this example and it really helps!
I’m new to JavaScript stuff and your code and comments are easy to read and understand.
I added a few lines to have the post to include data from other columns that maybe useful some others or at least for me.
Again thank you.
It isn’t working for me.
TypeError: table.row(…).data(…) is undefined
var objectId = table.row(rowId).data()[3];
Hi, great article, helped a lot.
I do have a question though, that i am struggling with and an answer could benefit many more people probably. I have some pages where I am using 2 or 3 datatables (tabs). What would be the easiest way to further improve solution described here to work with more than 1 table?
Thanks!
Good question! The only problem when working with multiple tables is that the amount of code almost doubles (with the exception of
updateDataTableSelectAllCtrl()
).I’m currently developing a plug-in that will greatly simplify the use of checkboxes in a table with much less code to write. It should be done in about a week and I will reference it in this article. This will allow to use it for multiple tables with great simplicity.
Stay tuned!
Hi, good day! Why am I returning a
undefined
?Instead of submitting the value. I test it to check if has a value by using alert. And it gives me
undefined
.Awesome!! Thanks a ton!! Exactly what I wanted! 🙂 If you could add some more examples like this in datatables, eg: adding dropdown boxes, radio buttons, text fields, etc that would be great! Thanks again!!
Great.. It worked for me. Thanks a lot for sharing ! 🙂
I have not tested this all environments but this works for me and is straightforward and needs no extensions other than DataTables.
A few explanations,
1. I have a div on the page with an id of
ResponseMessage
for feedback2. I have a class ‘AddMemberID’ on the checkboxes so only they are examined.
3.
_PoolID
is an id I have to pass as it is not part of the original form.4. I have these in a jQuery dialog box and
AddPoolID
andAddSelectedPersonnel
are hidden fields I populate when the dialog is saved.5. This occurs when the dialog submit button is clicked.
Brian, thanks for sharing. However it’s not clear from your code how you handle checkboxes and row selection. You can create an example on jsfiddle.net to share with everyone else here if you want.
Michael,
I think some of my code wasn’t posted in my email, I may have just copy and pasted wrong. I just created a Fiddle http://jsfiddle.net/thekonger/68kycvL3/ that shows how it works. The script uses the jQuery Datatables fnGetNodes method to get all table cells with a checkbox with a class of ‘RemoveMemberID’ and if checked adds the checkbox value to an array. To show it is also looking for the class I added one entry for John Doe that doesn’t include this class and if selected the value is ignored. This works across DataTable pagination.
In my project code it insert this array into a form field before submitting the form and then I pares over the values. In the Fiddle version it just shows an alert with the values.
Hi Michael and Everyone,
That’s so cool. I want to try it but I dont how to make it like that. I have copied the file include js,html,css, and jquery but It doesnt work like the demo. I have tried but nothing happens. If I run, just display the table and checkbox doesnt display. Why?
Would you like to help me? What should I do, so I can try it and see like the demo.
Please
Thank you
Hi,
Firstly, thanks you for creating this plugin and it is great and useful.
I would like to ask/do below thing :
(1) Some checkboxs ( row ) will be disabled based on data value. ( it is done by rowCallback )
(2) When user click select all, only enabled checked box need to be checked than all.
Please could you help for No.2 ?
Thanks in advance !
This is great, but How can I use with AngularJS?
Hi how about enabling and disabling submit button according to checkboxes status? So when I didn’t select any submit button will be disabled and when I select atleast one, it will be enabled. Can it be done?
Sure, see this jsFiddle. Add
$('#btn-submit').prop('disabled', (!rows_selected.length));
and make submit button disabled initially by addingdisabled
property.Thanks, is there also a way how to do this with your plugin?
Hi,
I have a custom dropdown with two values select all & unselect all. If I choose select all, can i get all page data in selected and If I choose unselect all, can i get all page data in unselected. Is it possible with your code ?
Thanks in advance
I’ve included the Column to check everything and like it, however, my boss wants to have a header on it with “Select All” when none of the checkbox are selected, then when all or some are selected it would be “Deselect All”. When I do something like this:
It ends up taking the column header checkbox away… which isn’t the desired effect. It does change the header name though…
Anyone have suggestions?
You can do it as shown in this example. However I would not recommend to do it that way, and it takes extra space in the heading.
Very nice work, it worked for me, only that I now want my data to come from a mysql database, how do I do that ??
Thanks! You need to write a server-side script in the language of your choice that will return data in JSON format, see documentation for more details.
Thanks for sharing
i have one doubt how can i post selected table data to post another aspx page
any one can help me
I very much appreciate people that create plugins so not at all trying to disparage their work, but this can be accomplished without any plugin; just jQuery and some JavaScript. I created a Fiddle http://jsfiddle.net/thekonger/68kycvL3/ that shows how it works. The script uses the jQuery Datatables fnGetNodes method to get all table cells with a checkbox with a class of ‘RemoveMemberID’ and if checked adds the checkbox value to an array. To show it is also looking for the class I added one entry for John Doe that doesn’t include this class and if selected the value is ignored and will not show as being selected. This works across DataTable pagination.
In my project code it insert this array into a form field before submitting the form and then I pares over the values. In the Fiddle version it just shows an alert with the values. Adding functions to uncheck/check all, getting tallies, etc. can all easily be done with JS and jQuery.
Brian, thank you for detailed comment and example. Your example will not work when server-side processing mode is used. Also you don’t have “Select all” and row selection mechanism . Basically this is what code in my article does beyond checkbox displaying and retrieval. In client-side processing mode it’s much simple but I wanted to provide universal solution.
How to select particular rows using checkbox and send them to server class?