multi nested datatables

multi nested datatables

harjmankooharjmankoo Posts: 11Questions: 2Answers: 0

Hi All
I have seen the following discussion back in 2015 (https://datatables.net/forums/discussion/28700/multi-nested-child-rows) which was basically just closed. Is there an update to this. Is there a way to multi-nest datatables. I have found plenty of examples of parent/child which work fine as child is usually a simple table construction but I have not seen any with parent/child/child-of-child/ etc.
Harj

This question has an accepted answers - jump to answer

Answers

  • kthorngrenkthorngren Posts: 21,341Questions: 26Answers: 4,954
    Answer ✓

    This blog shows how to create the child row as a Datatable along with using Editor. If you don't need the Editor you can ignore that part of the config.
    https://datatables.net/blog/2019-01-11

    IF you need multiple levels you can expand the example to the number of levels desired.

    Kevin

  • harjmankooharjmankoo Posts: 11Questions: 2Answers: 0

    Thanks kthorngren,
    I will see if I can follow it and implement it.
    Will post back results good or bad :-)
    Harj

  • harjmankooharjmankoo Posts: 11Questions: 2Answers: 0

    Hi kthorngren
    That worked brilliantly. I have gone to three levels of datatables and all work as expected. Very clean code and thankfully simple enough for even me to understand.
    I am using datatables with server-side PHP to retrieve data via ajax from a mysql db. I am happy to post an abridged version of my code if forum participants would like to see it. Please let me know if that would be useful and also where I would put my example.
    Thanks again.
    Harj

  • mgeyermgeyer Posts: 20Questions: 0Answers: 0

    @harjmankoo would be great if you could share your code - I'm trying to build it up.

    maybe you can share it here: http://live.datatables.net/

    thank you!
    mg

  • perreraperrera Posts: 1Questions: 0Answers: 0

    I can't make it work. Can any of you help me?

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

    Hi @perrera ,

    We're happy to take a look, but as per the forum rules, please link to a test case - a test case that replicates the issue will ensure you'll get a quick and accurate response. Information on how to create a test case (if you aren't able to link to the page you are working on) is available here.

    Cheers,

    Colin

  • harjmankooharjmankoo Posts: 11Questions: 2Answers: 0

    Sorry All especially mgeyer and perera. I will put code on as soon as I am able.
    Harj

  • harjmankooharjmankoo Posts: 11Questions: 2Answers: 0

    Hi All
    Here is an abridged version of the code. I have reduced my code to basics so you can use it as a template.
    This is on version 1.10 datatable
    Javascript/PHP and MySQL

    HTML

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <script src="scripts/getdata.js" language="javascript" type="text/javascript"></script>
            
            
        </head>
        <body>
            <div>
                <div class="panel panel-primary">
                    <div class="panel-heading">HEADING</div>
                    <div class="panel-body">
                        <table class='table table-striped table-responsive table-bordered small' id='MAINDataTable' style="width: 100%; font-size: 10px;">
                            <thead>
                                <tr>
                                    <th></th> 
                                    <th>ColumnNameMainField1</th>
                                    <th>ColumnNameMainField2</th>
                                </tr>
                            </thead>
                            <tbody>
                            </tbody>
                        </table>
                    </div>
                </div>
                
            </div>
            
           
            
        </body>
    </html>
    

    JS (getdata.js)

    function loadPalletAwait()
    {
        var MAINDataTable = $('#MAINDataTable').DataTable({
            processing: true,
            serverSide: true,
            destroy: true,
            searching: false,
            paging: true,
            pageLength: 10,
            ordering:  true,
            lengthChange: false,
            info: true,
            ajax: {
                url: "getdata.php",
                type: "GET",
                data: {"0": "function1",
                       
                }
            },
            columns: [
                {
                className:'details-control',
                orderable: false,
                data: null,
                defaultContent: '',
                width:'5%'
                
                },
                { data: "DisplayMainField1" },
                { data: "DisplayMainField2" }
                
            ],
            select: {
                style: "single"
            }
    
        });
                                
       
       
       $('#MAINDataTable tbody').on('click', 'td.details-control', function (event) {
           
            event.stopImmediatePropagation();
            var tr  = $(this).closest('tr'),
               row = $('#MAINDataTable').DataTable().row(tr);
    
            
           if (row.child.isShown()) {
               destroyChild(row);
               tr.removeClass('shown');
    
           }
           else {
                displayChildOfTable1(row,row.data().FindField1); 
                tr.addClass('shown');
                
           }
           
    
        });
        
         
         
    }  /* Load Line */
    
    function displayChildOfTable1(row,$Find1)
    {
        
        string='<table class="DTTable2 table table-striped table-responsive table-bordered small" id="" style="width: 100%; font-size: 10px;">';
        string = string + '<thead>';
        string = string + '<tr>';
        string = string + '<th></th>'; 
        string = string + '<th>Table2Field1</th>';
        string = string + '<th>Table2Field2</th>';
        string = string + '</tr>';
        string = string + '</thead> ';
        string = string + '</table>';
        var table = $(string);
        
    
        // Display it in the child row
        row.child( table ).show();
     
        // Initialise as a DataTable
        
         var Table2 = table.DataTable({
            processing: true,
            serverSide: true,
            destroy: true,
            searching: false,
            paging: true,
            pageLength: 10,
            ordering:  true,
            lengthChange: false,
            info: true,
            ajax: {
                url: "getdata.php",
                type: "GET",
                data: {"0": "function2",
                       "Find": $Find1
                       
                }
            },
            columns: [
                {
                className:'details-control2',
                orderable: false,
                data: null,
                defaultContent: '',
                width:'5%'
                
                },
                { data: "Field1" },  
                { data: "Field2" }
                
                
            ],
            select: {
                style: "single"
            }
            
    
        });
                                
       
        $('.DTTable2 tbody').on('click', 'td.details-control2', function (event) {
           
            
            
            event.stopImmediatePropagation();
            var tr  = $(this).closest('tr'),
               row = $('.DTTable2').DataTable().row(tr);
    
            
           if (row.child.isShown()) {
               destroyChild2(row);
               tr.removeClass('shown');
    
           }
           else {
                displayChildOfTable2(row,row.data().FindField2); 
                tr.addClass('shown');
                
           }
           
    
        });
        
        
        
        
        
         
    }  
    
    function displayChildOfTable2 ( row,$Find2 ) {
         
         // This is the table we'll convert into a DataTable
         // Note that id is blank. This is also important as id has to be unique which it cant be if we are 
         // creating the same table over and over again. Left as blank will prevent system getting confused
         // Can leave id completely out but left in to make it more obvious what we are doing
         
         string='<table class="DTTable2 table table-striped table-responsive table-bordered small" id="" style="width: 100%; font-size: 10px;">';
         string = string + '<thead>';
        string = string + '<tr>';
        string = string + '<th></th>'; 
        string = string + '<th>Table3Field1</th>';
        string = string + '<th>Table3Field2</th>';
        string = string + '</tr>';
        string = string + '</thead> ';
        string = string + '</table>';
        var table = $(string);
        
        // Display it in the child row
        row.child( table ).show();
     
        // Initialise as a DataTable
        
         var Table3 = table.DataTable({
            processing: true,
            serverSide: true,
            destroy: true,
            ajax: {
                url: "getdata.php",
                type: "GET",
                data: {"0": "function2",
                       "Find": $Find2
                       
                       
                }
            },
            columns: [
                {
                className:'details-control3',
                orderable: false,
                data: null,
                defaultContent: '',
                width:'5%'
                
                },
                { data: "field1" },  
                { data: "field2" }
                
           ],
            searching: false,
            paging: true,
            pageLength: 10,
            ordering:  true,
            lengthChange: false,
            info: true,
            select: {
                style: "single"
            },
             
        });
    
    
        
         
    }
    
    function destroyChild(row) {
        var table = $("Table2", row.child());
        table.detach();
        table.DataTable().destroy();
     
        // And then hide the row
        row.child.hide();
    }
    function destroyChild2(row) {
        var table = $("Table3", row.child());
        table.detach();
        table.DataTable().destroy();
     
        // And then hide the row
        row.child.hide();
    }
    

    CSS

    // This is just for the + and - buttons which expand and close the child rows.
    // You can use any image that you have available
    td.details-control {
    
        background: transparent url(../images/details_open.png) no-repeat center center;
        
    
        cursor: pointer;
    
    }
    
    tr.shown td.details-control {
    
        background: transparent url(../images/details_close.png) no-repeat center center;
    
    }
    
    td.details-control2 {
    
        background: transparent url(../images/details_open.png) no-repeat center center;
        
    
        cursor: pointer;
    
    }
    
    tr.shown td.details-control2 {
    
        background: transparent url(../images/details_close.png) no-repeat center center;
    
    }
    
    td.details-control3 {
    
        background: transparent url(../images/details_open.png) no-repeat center center;
        
    
        cursor: pointer;
    
    }
    
    tr.shown td.details-control3 {
    
        background: transparent url(../images/details_close.png) no-repeat center center;
    
    }
    
    
  • veliveli Posts: 1Questions: 0Answers: 0

    Hi all,
    @harjmankoo thanks for your code. I try to make it in angularjs and it doesnt show the table. Here is my code and problem:

    I would really appreciate your help

      var data = [
    
                {
    
                    "DT_RowId": "row_1000",
    
                    "clientID": 10407,
    
                    "clientName": "DowDuPont Inc.",
    
                    "wip": "$583,341 ",
    
                    "ar": "$646,385",
    
                    "ar0_30": "$500,389",
    
                    "ar31_60": "$129,016",
    
                    "ar61_90": "$15,822",
    
                    "ar91_120": "$1,122",
    
                    "ar121_": "$31",
    
                    "suspense": "$8,247"
    
                },
    
                {
    
                    "DT_RowId": "row_1001",
    
                    "clientID": 36526,
    
                    "clientName": "Maxwell Technologies, Inc.",
    
                    "wip": "$576,521 ",
    
                    "ar": "$930,316",
    
                    "ar0_30": "$522,322",
    
                    "ar31_60": "$378,794",
    
                    "ar61_90": "$25,030",
    
                    "ar91_120": "$3,629",
    
                    "ar121_": "$494",
    
                    "suspense": "$6,931"
    
                }
            ];
    
            var childEditors = {};  // Globally track created chid editors
            var childTable;
            var childTable2;
    
            /*   ----------------  Definition Haupttabelle------------------------------*/
            vm.show_child = false;
            vm.show_inChildRow = false;
    
            vm.example_dtOptions = create_dt_options();
            vm.example_dtColumns = create_dt_columns();
            vm.example_dtInstance = {};
    
            function create_dt_options() {
                var _data = data;
                var _dt_options = DataTableService.create_dt_options_local_data(vm, _data);
    
                _dt_options.rowCallback = rowCallback;
                _dt_options.createdRow = createdRow;
    
                return _dt_options;
            }
    
            function create_dt_columns() {
                var _columns = [
                    {
                        className: 'details-control',
                        orderable: false,
                        data: null,
                        defaultContent: ''
                    },
                    {data: "clientID"},
                    {data: "wip"},
                    {data: "ar"},
                    {data: "ar0_30"},
                    {data: "ar31_60"},
                    {data: "ar61_90"},
                    {data: "ar91_120"},
                    {data: "ar121_"},
                    {data: "suspense"}
                ];
    
                return _columns;
            }
            
            // Callback-Funktion für ganze Zeile (hier: Click-Event auf Zeile)
            // Add event listener for opening and closing first level childdetails
            function rowCallback(tabRow, data, dataIndex) {
                $(tabRow).unbind("click");
                $(tabRow).bind('click', function (){
                    $scope.$apply(function () {
                        $('#example tbody').on('click', 'td.details-control', function (event) {
                            event.stopImmediatePropagation();
                            var tr  = $(this).closest('tr'),
                                row = $('#example').DataTable().row(tr);
    
                            if (row.child.isShown()) {
                                destroyChild(row);
                                tr.removeClass('shown');
    
                            }
                            else {
                                displayChildOfTable1(row,row.data());
                                tr.addClass('shown');
    
                            }
    
                        })
                        /*
                        event.stopImmediatePropagation();
                        var tr = $(tabRow);
                        // console.log("tr",tr);
                        var table = vm.example_dtInstance.DataTable;
                        var row = table.row(tr);
    
                        console.log("tr", tr);
                        console.log("row", row);
    
    
                        if (row.child.isShown()) {
                            // This row is already open - close it
                            row.child.hide()
    
                        /!*    var table = $("#dataTable_child1");
                                table.detach();
                                table.DataTable().destroy();
    *!/
                                // And then hide the row
                                row.child.hide();
                            tr.removeClass('shown');
                        }
    
                        else {
                           // row.child( format(row.data())).show;
                            console.log("row.data()",row.data());
                            console.log("tabRow", tabRow)
                            // Open this row
                          //  var table = $('#dataTable_child1');
    
                            //Display it in the child row
    
                            row.child.show();
    
                          //  $timeout(function(){displayChildOfTable1(row);},100);
                            tr.addClass('shown');
                        }*/
                    });
    
                });
            }
    
            function createdRow(row, data, dataIndex) {
                // Recompiling so we can bind Angular directive
                $compile(angular.element(row).contents())($scope);
            }
    
            /*  ---------------------------------------------------------------------------------------------------------------*/
    
            /*   --------------------------------  Anfang Definition Child1 Tabelle--------------------------------------------*/
    
    
            function displayChildOfTable1(row, data) {
    
                vm.child1_dtOptions = create_dt_options_child1();
                vm.child1_dtColumns = create_dt_columns_child1();
                vm.child1_dtInstance = {};
    
                function create_dt_options_child1() {
                    var _data = data_child;
                    var _dt_options = DataTableService.create_dt_options_local_data(vm, _data);
    
                    _dt_options.rowCallback_child = rowCallback_child1;
                    _dt_options.createdRow_child = createdRow_child1;
                    return _dt_options;
                }
    
                function create_dt_columns_child1() {
                    var _columns = [
                        {
                            className: 'details-control',
                            orderable: false,
                            data: null,
                            defaultContent: ''
                        },
                        {
                            data: "wip",
                            title: "wip"
                        },
                        {data: "ar"},
                        {data: "ar0_30"},
                        {data: "ar31_60"},
                        {data: "ar61_90"},
                        {data: "ar91_120"},
                        {data: "ar121_"},
                        {data: "suspense"}
                    ];
    
                    return _columns;
                }
    
                function createdRow_child1(row, data, dataIndex) {
                    // Recompiling so we can bind Angular directive
                    console.log('hi vom created_child1');
                    $compile(angular.element(row).contents())($scope);
                }
    
                var string = '<table id="dataTable_child1"' +
                    ' datatable=""' + ' dt-options="vm.child1_dtOptions"' +
                    ' dt-columns="vm.child1_dtColumns"' +
                    ' dt-instance="vm.child1_dtInstance"' +
                    ' class="DTTable2 kiss-grid">';
                string = string + '</table>';
                var table = $(string);
    
                // Display it in the child row
                row.child( table ).show();
    
    
                // Callback-Funktion für ganze Zeile (hier: Click-Event auf Zeile)
                // Add event listener for opening and closing second level childdetails
                function rowCallback_child1(tabRow, data, dataIndex) {
                    console.log("hiiii")
                    $(tabRow).unbind("click");
                    $(tabRow).bind("click", function () {
                        $scope.$apply(function () {
                            //event.stopImmediatePropagation();
                            console.log("row", row);
                            console.log("data", data);
                            console.log("index", dataIndex);
                            console.log("click");
    
                            var tr = $(tabRow);
                            console.log("tr", tr);
                            var table = vm.child1_dtInstance.DataTable;
                            var row = table.row(tr);
    
                            if (row.child.isShown()) {
                                // This row is already open - close it
                                vm.show_child = false;
                                row.child.hide();
                                tr.removeClass('shown');
    
                                // Destroy the Child Datatable
                                //  $('#cl' + data.clientID).DataTable().destroy();
                            }
                            else {
                                // Open this row
    
                                //displayChildOfTable2( row);
    
                                tr.addClass('shown');
    
                            }
                        });
    
                    });
                }
            }
    
            function destroyChild(row) {
                var table = $("#example", row.child());
                table.detach();
                table.DataTable().destroy();
    
                // And then hide the row
                row.child.hide();
            }
        }
    

    Any Ideas why it does not show the child table?

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

    @veli We're happy to take a look, but as per the forum rules, please link to a test case - a test case that replicates the issue will ensure you'll get a quick and accurate response. Information on how to create a test case (if you aren't able to link to the page you are working on) is available here.

    Cheers,

    Colin

This discussion has been closed.