How can I expand all rows for multiple tables?

How can I expand all rows for multiple tables?

nightmare637nightmare637 Posts: 14Questions: 3Answers: 0

Is there a simple way for me to expand all the rows in multiple tables with a click of a button? I can call all of my tables with the

$('td table')

tag. And I have it set up to open and close rows based on clicking a button within that row:

        // Add event listener for opening and closing details
        $('td table').on('click', 'td.dt-control', function () {
            var tr = $(this).closest('tr');
            var row = mytable.row( tr );

            if ( row.child.isShown() ) {
                row.child.hide();
                tr.removeClass('shown');
            }
            else {
                row.child( format(row.data()) ).show();
                tr.addClass('shown');
            }
        } );

So far, this is what I'm trying:

$('#expandRows').change(function(){
    let checked = $(this).prop("checked");

    if(checked)
    {
        $('td table').DataTable().rows().every( function () {
            var $tr = $(this.node());
            this.child(format(this.data())).show();
            $tr.addClass('shown');
        });
    }
}

My idea is a mix of:

https://datatables.net/forums/discussion/comment/123560/#Comment_123560
https://www.gyrocode.com/articles/jquery-datatables-how-to-expand-collapse-all-child-rows/
https://stackoverflow.com/questions/62575674/expand-collapse-all-with-nested-table-jquery-datatables/62583040#62583040

But it just simply isn't working. The class for every single row on all of my tables are changing to the "shown" class correctly, but nothing is actually expanding. I'm fairly certain that my "this.data()" parameter I'm passing is wrong, but I'm not sure what else to put.

What am I doing wrong?

Replies

  • rf1234rf1234 Posts: 2,958Questions: 87Answers: 418
    edited December 2021

    I found a way to make a button that shows / hides all child rows of the rows selected. if a minority of child rows are expanded it shows all child rows; if a majority of child rows are expanded it hides all child rows.

    I also have that button for all rows on the respective page (not only the ones that are selected).

    All you would need to do is to expand that logic to comprise all of the tables on your page. Shouldn't bee too difficult.

    Since the showing / hiding takes a little bit of time I am showing a (forgot what it's called) loading thing: something that is blocking the page and displaying a "please wait" symbol. (I just forgot the words and don't recall them in my first language either.). The tool for this is called "busyLoad". But that is only one of many tools available for that purpose.

    Here are both buttons:

    //custom button to show all child rows of the rows selected (responsive extension)
        $.fn.dataTable.ext.buttons.showHideAllChildRowsSelected = {
            extend: 'selected',
            text: showHideAllChildRowsSelectedLabel,
            action: function ( e, dt, button, config ) {
                // https://www.gyrocode.com/articles/jquery-datatables-how-to-expand-collapse-all-child-rows/
                //dt.rows( ':not(.parent)', { selected: true } ).nodes().to$().find('td:first-child').trigger('click');
                $.busyLoadFull("show");
                var selParent;
                if ( dt.rows( ':not(.parent)', { selected: true } ).count() > 
                     dt.rows( '.parent',       { selected: true } ).count()    ) {
                    selParent = ':not(.parent)';
                } else {
                    selParent = '.parent';
                }
                setTimeout(function() {
                    var sel = dt.rows( selParent, { selected: true } ).nodes().to$();
                    //also possible: sel.find('td:first-child').trigger('click'); 
                    //               sel.promise()done(function ...
                    sel.find('td:first-child').trigger('click').promise().done(
                        function(){
                            $.busyLoadFull("hide");
                        } )
                }, 50);
            }
        };
        
        //custom button to show all child rows of the rows selected (responsive extension)
        $.fn.dataTable.ext.buttons.showHideAllChildRows = {
            text: showHideAllChildRowsSelectedLabel,
            name: "showHideAllChildRowsButton",
            action: function ( e, dt, button, config ) {
                // https://www.gyrocode.com/articles/jquery-datatables-how-to-expand-collapse-all-child-rows/
                //dt.rows( ':not(.parent)', { selected: true } ).nodes().to$().find('td:first-child').trigger('click');
                $.busyLoadFull("show");
                var selParent;
                if ( dt.rows( ':not(.parent)', { page: 'current' } ).count() > 
                     dt.rows( '.parent',       { page: 'current' } ).count()    ) {
                    selParent = ':not(.parent)';
                } else {
                    selParent = '.parent';
                }
                setTimeout(function() {
                    var sel = dt.rows( selParent, { page: 'current' } ).nodes().to$();
                    //also possible: sel.find('td:first-child').trigger('click'); 
                    //               sel.promise()done(function ...
                    sel.find('td:first-child').trigger('click').promise().done(
                        function(){
                            $.busyLoadFull("hide");
                        } )
                }, 50);
            }
        };
    
  • kthorngrenkthorngren Posts: 21,262Questions: 26Answers: 4,934

    I tried your code, lines 6-10, in a page with two tables and it only applied the shown class and opened rows for the first table. Counting the number of rows looped it showed 114 (56 * 2) but I think it looped the first table twice.

    Use something like this to get all the Datatable API's

    var tables = $('td table').DataTable();
    

    If you look at the tables variable you will see a context property that is an array of all the table API's. We will use the length of the context array to loop through each table. Then use rows().every() to loop all the rows in that table. For example:
    http://live.datatables.net/yaputuke/1/edit

      $('button').on('click', function () {
        var tables = $('table').DataTable();
        for (i=0; i<tables.context.length; i++) {
          table = tables.table(i);
          table.rows().every( function () {
            var $tr = $(this.node());
            this.child(format(this.data())).show();
            $tr.addClass('shown');
          });
        }
      });
    

    Kevin

  • nightmare637nightmare637 Posts: 14Questions: 3Answers: 0

    Thank you BOTH for your replies! It was very helpful.

    I ended up using @kthorngren 's solution. Just one quick thing - since I don't want to create another topic. When I provide functionality for closing them:

                    for (i=0; i < mytable.context.length; i++)
                    {
                        table = mytable.table(i);
                        table.rows().every(function (){
                            let tr = $(this.node());
                            this.child().hide();
                            tr.removeClass('shown');
                        });
                    }  
    

    It works perfectly, except it doesn't change the minus signs (-) back to a plus sign(+). All the rows still collapse, and I don't see anything in developer tools as far as errors. Could I be overlooking something again?

  • nightmare637nightmare637 Posts: 14Questions: 3Answers: 0
    edited December 2021

    Well this is embarrassing...

    I left in the() in my this.child().hide(); statement. In other words, it should be:

    this.child.hide();
    

    instead of

    this.child().hide();
    

    It's working correctly now. Thanks again for the help!!!

    Edit: I don't know how to mark your question as an answer - the option went away. If you can let me know how to do this, I'd be happy to mark it as the answer. Thanks!

  • kthorngrenkthorngren Posts: 21,262Questions: 26Answers: 4,934

    Glad you found the problem :-). It doesn't look like you started this as a question to the option to mark it answered is not available. Not sue if an admin like @allan or @colin can mark it.

    Kevin

  • colincolin Posts: 15,240Questions: 1Answers: 2,599

    Exactly, it needs to be a question to have an 'answer'. But, yep, I think your comment will help other users find the answer!
    Colin

Sign In or Register to comment.