Datatables: How Can I Keep Child Rows Opened After The Ajax Reload
Solution 1:
To give an answer to the initial question (how to keep child rows open on DataTable AJAX reload), see the following implementation.
I use cookies to keep the children rows open and I am using the plugin js-cookie
found here.
It is better to have a unique identifier as a column of your table so that the re-opened rows are the right one.
$(function(){
var dt = $('#my_table').DataTable(...);
var reloadInterval = 10000; // milliseconds// Add extra-info rowdt_add_details('my_table', 'details-control', formatCallback, 'id');
var reloadCallback = function(json){
dt_reopen_rows('my_table', formatCallback, 'id')
};
// Reload AJAX source every X secondssetInterval(function(){
dt.ajax.reload(reloadCallback, false);
}, reloadInterval)
});
/**
* Format child row data.
*/functionformatCallback(d){
...
}
/**
* Show / Hide extra-info when clicking on the column identified by className.
* @param {String} selector - The HTML selector for the table.
* @param {String} className - The column class name that holds the extra-info.
* @param {Function} formatCallback - Function used to format the data of the
* child row.
* @param {String} cookieDataIndex - The data index to keep in cookie.
*/functiondt_add_details(selector, className, formatCallback, cookieDataIndex){
$(selector + ' tbody').on('click', 'td.' + className, function () {
var ckey = 'openRows_' + selector;
var openRows = Cookies.getJSON(ckey);
// Create cookie if never createdif (typeof openRows == 'undefined'){
Cookies.set(ckey, [], {'path': ''});
var openRows = Cookies.getJSON(ckey);
};
// Get current infovar tr = $(this).closest('tr');
var row = $(selector).DataTable().row(tr);
var id = row.data()[cookieDataIndex];
if (row.child.isShown()){
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
// Remove opened row from cookievar idx = openRows.indexOf(id);
openRows.splice(idx, 1);
Cookies.set(ckey, openRows, {path: ''});
}
else{
// Open this row
row.child(formatCallback(row.data())).show();
tr.addClass('shown');
// Add row 'id' field to cookieif (openRows.indexOf(id) < 0){
openRows.push(id);
}
Cookies.set(ckey, openRows, {path: ''});
}
// console.log("Opened rows: " + Cookies.getJSON('openRows_' + selector))
});
}
/**
* Show / Hide extra-info when clicking on the column identified by className.
* @param {String} selector - The HTML selector for the table.
* @param {Function} formatCallback - Function used to format the data of the
* the child row.
* @param {String} cookieDataIndex - The data index to keep in cookie.
*/functiondt_reopen_rows(selector, formatCallback, cookieDataIndex) {
var ckey = 'openRows_' + selector;
var openRows = Cookies.getJSON(ckey);
if (!openRows)
return;
var table = $(selector).DataTable(); // existing DataTable
$(table.rows().nodes()).each(function (idx, tr) {
var row = table.row(tr);
var id = row.data()[cookieDataIndex]
if (openRows.indexOf(id) >= 0) {
// console.log("Id " + id + " found in previously opened row. Re-opening.")
$(tr).addClass("shown");
row.child(formatCallback(row.data())).show();
}
});
}
Solution 2:
As i have understood you are clearing previous table with new table created by data coming from ajax. You will have to save state of opened rows and whenever you are done with refreshing table expand rows with your saved state.
Solution 3:
Using this solution, every row in your table should have a row id. For more details see: https://datatables.net/reference/option/rowId
HTML
<scriptsrc="http://code.jquery.com/jquery-latest.min.js"type="text/javascript"></script><linktype="text/css"href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css"><scriptsrc="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
table id="example" class="display" style="width:100%">
<thead><tr><th></th><th>Name</th><th>Position</th><th>Office</th><th>Salary</th></tr></thead><tfoot><tr><th></th><th>Name</th><th>Position</th><th>Office</th><th>Salary</th></tr></tfoot></table>
Javascript
/* Function to create a new row, fell free to render your code here */functionformat(d) {
// `d` is the original data object for the rowreturn'<table cellpadding="5" cellspacing="0" border="0" style="padding-left:50px;">' +
'<tr>' +
'<td>Full name:</td>' +
'<td>' + d.name + '</td>' +
'</tr>' +
'<tr>' +
'<td>Extension number:</td>' +
'<td>' + d.extn + '</td>' +
'</tr>' +
'<tr>' +
'<td>Extra info:</td>' +
'<td>And any further details here (images etc)...</td>' +
'</tr>' +
'</table>';
}
functiononClickEventListener() {
var tr = $(this).closest('tr');
var row = table.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
}
else {
// Open this row
row.child(format(row.data())).show();
tr.addClass('shown');
}
let currentRowID = "#" + ($(this).closest('tr').attr('id'));
if ($.inArray(currentRowID, rowIds) !== -1) {
//Row is closed, remove row ID from rowIDs arrayvar index = rowIds.indexOf(currentRowID);
if (index !== -1) rowIds.splice(index, 1);
rowIds.filter(function (val) {
return val
});
} else {
//Row is opened, add row ID to rowIDs array
rowIds.push(currentRowID);
}
}
$(document).ready(function () {
let rowIds = [];
var table = $('#example').DataTable({
"ajax": "{{ path('your_data_source') }}",
"columns": [
{
"className": 'details-control',
"orderable": false,
"data": null,
"defaultContent": ''
},
{"data": "name"},
{"data": "position"},
{"data": "office"},
{"data": "salary"}
],
"order": [[1, 'asc']]
});
// Add event listener for opening and closing the row
$('#example tbody').on('click', 'td.details-control', onClickEventListener);
//set interval to update datatablesetInterval(function () {
table.ajax.reload(function () {
//Iterate through all the open rows and open them again <--Value is set in the onClickEventListener function
table.rows(rowIds).every(function (row, index, array) {
table.row(row).child(format(this.data())).show();
this.nodes().to$().addClass('shown');
//Add a minus icon for the open rowthis.nodes().to$().children('td:first').html('<img style="max-width: 30px;; max-height: 100%;object-fit: contain" src=' + '{{ asset('img/datatables/icon_minus.png') }}' + ' ></img>');
});
//Set to false if you don't want the paging to reset after ajax load,otherwise true
}, false);
}, 1000);
});
Solution 4:
Try to store the index value of rows (in global) , which are opened
After the table reloaded, call the following method
functionopenChildByIndex(){
let row = table.row('globally stored index'); //place your index here
row.child(format(row.data())).show();
$(row.node()).addClass('shown');
}
Post a Comment for "Datatables: How Can I Keep Child Rows Opened After The Ajax Reload"