问题
I'm using an Ajax source to generate the table. This one is refreshed every 5000 ms and when a child row is opened it's then closed by the table's redraw. How can I keep these ones opened?
My code:
/* Formatting function for row details - modify as you need */
function format ( d ) {
// `d` is the original data object for the row
return '<p>Text in child row</p>';
}
$(document).ready(function() {
$('#table').DataTable( {
...
} );
var tr;
var row;
$('#table tbody').on('click', 'td.details-control', function () {
if (tr !== null && tr !== undefined && row !== null && tr !== undefined) {
row.child.hide();
tr.removeClass('shown');
}
tr = $(this).closest('tr');
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');
}
} );
$.fn.dataTable.ext.errMode = 'none';
var table = $('#table').DataTable();
setInterval( function () {
table.ajax.reload( function () {
if ( row.child.isShown() ) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
}
else {
if (tr.hasClass('shown')) {
// Open this row
row.child( format(row.data()) ).show();
tr.addClass('shown');
}
}
} );
}, 5000 );
$('table td .details-control').html('<button><i class="fa fa-plus"></i></button>');
} );
See Child rows example and ajax.reload() method for reference.
- After some research I've seen that people suggest using cookies in jQuery
回答1:
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.
回答2:
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 row
dt_add_details('my_table', 'details-control', formatCallback, 'id');
var reloadCallback = function(json){
dt_reopen_rows('my_table', formatCallback, 'id')
};
// Reload AJAX source every X seconds
setInterval(function(){
dt.ajax.reload(reloadCallback, false);
}, reloadInterval)
});
/**
* Format child row data.
*/
function formatCallback(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.
*/
function dt_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 created
if (typeof openRows == 'undefined'){
Cookies.set(ckey, [], {'path': ''});
var openRows = Cookies.getJSON(ckey);
};
// Get current info
var 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 cookie
var 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 cookie
if (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.
*/
function dt_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();
}
});
}
回答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
<script src="http://code.jquery.com/jquery-latest.min.js"
type="text/javascript"></script>
<link rel="stylesheet" type="text/css"
href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<script src="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 */
function format(d) {
// `d` is the original data object for the row
return '<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>';
}
function onClickEventListener() {
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 array
var 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 datatable
setInterval(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 row
this.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);
});
来源:https://stackoverflow.com/questions/31771733/datatables-how-can-i-keep-child-rows-opened-after-the-ajax-reload