Datatables: How can I keep child rows opened after the Ajax reload

两盒软妹~` 提交于 2019-12-24 12:23:13

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!