JSON data with Datatable containing child rows

JSON data with Datatable containing child rows

cyrillecyrille Posts: 4Questions: 1Answers: 0

Hi,

I couldn't find any example of JSON data to feed a Datatable with child rows, here is my table in HTML with static data, I would like to refresh data using ajax and JSON"

 <table id="tablespaces-datatable" class="table table-striped">
                                        <thead>
                                            <tr>
                                                <th></th>
                                                <th><strong>Tablespace Name</strong></th>
                                                <th class="text-center"><strong>Space Used (MB)</strong></th>
                                                <th class="text-center"><strong>Max Size (MB)</strong></th>
                                                <th class="text-center"><strong>Max Used (%)</strong></th>
                                                <th class="text-center"><strong>Condition</strong></th>
                                                <td class="text-center"><strong>Trend</strong></td>
                                            </tr>
                                        </thead>
                                        <tbody>
                                            <tr>
                                                <td></td>
                                                <td>TABLESPACE 1</td>
                                                <td class="text-center">172215</td>
                                                <td class="text-center">200000</td>
                                                <td class="text-center"><span>88%</span></td>
                                                <td class="text-center"><span>< 92%</span></td>
                                                @*sparkline chart for the trend, see chart definition in the scripts*@
                                                <td class="text-center"><span class="inlinesparkline">40,40,40,42,43,43</span></td>
                                            </tr>
                                            <tr>
                                                <td></td>
                                                <td>TABLESPACE 2</td>
                                                <td class="text-center">120000</td>
                                                <td class="text-center">200000</td>
                                                <td class="text-center"><span>65%</span></td>
                                                <td class="text-center"><span>< 92%</span></td>
                                                @*sparkline chart for the trend, see chart definition in the scripts*@
                                                <td class="text-center"><span class="inlinesparkline">40,40,40,42,43,43</span></td>
                                            </tr>
                                            <tr>
                                                <td></td>
                                                <td>TABLESPACE 3</td>
                                                <td class="text-center">120</td>
                                                <td class="text-center">240</td>
                                                <td class="text-center"><span>50%</span></td>
                                                <td class="text-center"><span>< 80%</span></td>
                                                @*sparkline chart for the trend, see chart definition in the scripts*@
                                                <td class="text-center"><span class="inlinesparkline">40,40,40,42,43,43</span></td>
                                            </tr>
                                        </tbody>
                                    </table>

And here is the javascript:

   var tablespaces_datatable = $('#tablespaces-datatable').DataTable({
            dom: 'Bfrtlp',
            "autoWidth": false,
            responsive: {
                details: {
                    type: 'column',
                    target: 'tr'
                }
            },
            columnDefs: [ {
                className: 'details-control',
                orderable: false,
                targets:   0
            }],
            buttons: [
               'excelHtml5',
               'csvHtml5',
               'copyHtml5'
            ],           
            order: [ 1, 'asc' ]
        });

  tablespaces_datatable.rows().every( function () {
            this
                .child(
                    $(                  '<div class="slider">'+
                                         '<table class="table table-striped">'+
                                            '<thead>'+
                                                '<tr class="detail-header">'+
                                                    '<th><strong>Datafile Name</strong></th>'+
                                                    '<th class="text-center"><strong>Datafile Size (MB)</strong></th>'+
                                                    '<th class="text-center"><strong>Autoextend</strong></th>'+
                                                    '<th class="text-center"><strong>Datafile MaxSize (MB)</strong></th>'+                                                     
                                                '</tr>'+
                                            '</thead>'+
                                            '<tbody>'+
                                                '<tr>'+
                                                    '<td>DATAFILE 1</td>'+
                                                    '<td class="text-center">172215</td>'+                                                    
                                                    '<td class="text-center"><i class="fa fa-check-square-o text-navy"></i></td>'+
                                                    '<td class="text-center">250000</td>'+                                                 
                                                '</tr>'+
                                                '<tr>'+
                                                    '<td>DATAFILE 2</td>'+
                                                    '<td class="text-center">120000</td>'+                                                    
                                                    '<td class="text-center"><i class="fa fa-times text-danger"></i></td>'+
                                                    '<td class="text-center">1220000</td>'+                                                 
                                                '</tr>'+
                                            '</tbody>'+
                                        '</table>'+
                                       '</div>'
                    )
                )            
        } );

Is there a way to create this table using JSON data ?

Thanks

Cyrille

This question has an accepted answers - jump to answer

Answers

  • segfaulcoredumpsegfaulcoredump Posts: 5Questions: 0Answers: 1
    edited April 2017

    Yes

    Short answer: Look at http://thetcr.com/tcr/results/ppa/2016/ for an example of how I used child rows with responsive for the race results.

    There is a lot going on there (responsive, buttons, filtering, etc) so hopefully this will break it down a bit:

    The base table is given an id of "results" and the javascript for the base table is setup as such:

    var oTable = $('#results').DataTable({
    <base datatable stuff here>
    })
    

    The json is just a huge (2meg) inline data structure. It has several layers deep.

    Then under the fnInitComplete section, you see the following:

    // Add event listener for opening and closing details
        $('#results tbody').on('click', 'tr', function () {
            var tr = $(this).closest('tr');
            var row = oTable.row( tr );
     
            if ( row.child.isShown() ) {
                // This row is already open - close it
                row.child.hide();
                tr.removeClass('parent');
            }
            else {
                // Open this row
                row.child( childData(row.data()), 'child' ).show();
                tr.addClass('parent');
            }
        } );
    

    I setup a child row render that looks like this:

    function childData ( rData) {
    <bla, bla, bla>
    }
    

    In this chilData function, you see things like this:

    var data = '<div class="detail">';
    data += '<div class="row">';
    data += '<div class="participant">' // personal
    data += '<div class="part-name">' + rData.full_name + '</div>';
    data += '<div class="part-stats">Bib: ' + rData.bib + '</div>';
    data += '<div class="part-stats">Age: ' + rData.age + '   Sex: ' + rData.sex + '   AG: ' + rData.ag + '</div>';
    data += '<div class="part-stats">' + rData.city + ', ' + rData.state + '</div>';
    
    return data;
    

    I hope this points you in the right direction.

  • cyrillecyrille Posts: 4Questions: 1Answers: 0

    Hi segfaulcoredump,

    Thanks for you explanation, I figured out I can do that but here you create a html child row out of the JSON data, I could pass directly the JSON to the Datatable in a certain format and Datatable will understand the rows and child rows directly, maybe it's not possible.

    Thanks

    Cyrille

  • segfaulcoredumpsegfaulcoredump Posts: 5Questions: 0Answers: 1

    As I understand your question, it is possible.

    It gets a bit complicated since it appears that you have DOM sourced data for the initial table and want to use json for the child. To do that you will need some sort of key in the dom to reference the data you want in the child.

    In my example, I build the child on the fly when folks click on the row per the datatables child documentation. I don't try and do it in a .rows().every() function and pre-compute it all.

    I have the onClick function pull the data for that row. Since I use the same json source for both the main table and the child, I can do that. In your case, you will need to pull some field from the dom source that can be used as a key into your json data. Then you can reference it in your child display function.

  • cyrillecyrille Posts: 4Questions: 1Answers: 0

    I'm really sorry segfaulcoredump, I think I have not been clear enough.
    In fact my current code does not reflect what i'm trying to achieve, It was just a code to validate how the output will be like.
    I have a tablespace and for each tablespace there will be a set of datafiles.
    What I want to do is to get the whole thing (parent and children) at the same time using ajax and load it as a JSON object.
    What I want to know is , how should I format the JSON for the DataTable to understand the Parent/Child relationship.

    Thanks a lot for your help.

    Cyrille

  • segfaulcoredumpsegfaulcoredump Posts: 5Questions: 0Answers: 1
    Answer ✓

    The link I provided is an example of how to do that. (It adds a bunch of other stuff too)

    Here is the annotated version:

    In the page's html section I have table header with an ID so that I can find it later. No data. My example looks like this:

      <TABLE id="results" class="display responsive dtr-column nowrap" > 
        <thead><tr>
          <th class="all"></th>
          <th data-priority="2">OA#</th>
          <th data-priority="4">SEX#</th>
          <th data-priority="6">AG#</th>
          <th data-priority="20">Bib</th>
          <th data-priority="21">Age</th>
          <th data-priority="3">Sex</th>
          <th data-priority="5">AG</th>
          <th data-priority="1" class="all">Name</th>
          <th data-priority="41">City</th>
          <th data-priority="40">ST</th>
          <th data-priority="100">1 Mile</th>
          <th data-priority="100">NoName</th>
          <th data-priority="100">Barr Camp</th>
          <th data-priority="100">A-Frame</th>
          <th data-priority="100">1 to Go</th>
          <th data-priority="80">Barr Camp</th>
          <th data-priority="80">Barr Camp to Summit</th>
          <th data-priority="80">Treeline to Summit</th>
          <th data-priority="1" class="all">Finish</th>
          <th data-priority="90">Gun</th>
          <th data-priority="85">Pace</th>
    </tr></thead>
    </table>
    

    The first column is a dummy column for the control that puts the green + sign in there.

    The JSON data looks like this:

    var resultsData = [
        {
            "bib": "70",
            "age": "32",
            "sex": "M",
            "ag": "30-34",
            "full_name": "Joseph Gray",
            "first_name": "Joseph",
            "middle_name": "",
            "last_name": "Gray",
            "city": "Colorado Spgs",
            "state": "CO",
            "country": "",
            "note": "",
            "oa_place": "1",
            "sex_place": "1",
            "ag_place": "1",
            "splits": {
                "split_1_1 Mile": {
                        "display": "0:05:48",
                        "delta_time": "0:05:48",
                        "pace": "5:48/mi",
                        "sort": "0:05:48"
                },
                "split_2_NoName": {
                        "display": "0:35:27",
                        "delta_time": "0:29:39",
                        "pace": "8:59/mi",
                        "sort": "0:35:27"
                },
                "split_3_Barr Camp": {
                        "display": "1:00:53",
                        "delta_time": "0:25:26",
                        "pace": "7:42/mi",
                        "sort": "1:00:53"
                },
                "split_4_A-Frame": {
                        "display": "1:27:45",
                        "delta_time": "0:26:52",
                        "pace": "10:20/mi",
                        "sort": "1:27:45"
                },
                "split_5_1 to Go": {
                        "display": "1:50:46",
                        "delta_time": "0:23:00",
                        "pace": "10:51/mi",
                        "sort": "1:50:46"
                }
            },
            "segments": {
                "segment_Barr Camp": {
                        "display": "1:00:53",
                        "sort": "1:00:53",
                        "oa_place": "1",
                        "sex_place": "1",
                        "ag_place": "1"
    ,
                        "pace": "8:00/mi"
                },
                "segment_Barr Camp to Summit": {
                        "display": "1:04:35",
                        "sort": "1:04:35",
                        "oa_place": "1",
                        "sex_place": "1",
                        "ag_place": "1"
    ,
                        "pace": "11:17/mi"
                },
                "segment_Treeline to Summit": {
                        "display": "0:37:42",
                        "sort": "0:37:42",
                        "oa_place": "1",
                        "sex_place": "1",
                        "ag_place": "1"
    ,
                        "pace": "12:05/mi"
                }
            },
            "start_display": "7:00:42",
            "finish_split_delta": "0:14:42",
            "finish_split_pace": "14:42/mi",
            "finish_display": "2:05:28",
            "finish_sort": "2:05:28",
            "gun_display": "2:05:40",
            "gun_sort": "2:05:40",
            "finish_pace": "9:25/mi"
        }
    ]
    

    ...

    (that is one row, there are 1790 in the example I provided that follow a similar structure.

    Now we setup the DataTable object, using the "results" table in the html portion of the file, pointing the data to the resultsData I outlined above, and defining the columns.

    var oTable = $('#results').DataTable({
           data: resultsData,
            "columns": [
               { "data": null, "defaultContent": "", className: 'control', orderable: false, targets:   0 },
               { "data": "oa_place" },
               { "data": "sex_place" },
               { "data": "ag_place" },
               { "data": "bib" },
               { "data": "age" },
               { "data": "sex" },
               { "data": "ag" },
               { "data": "full_name" },
               { "data": "city" },
               { "data": "state" },
               { "data": "splits.split_1_1 Mile", 
                    "render": {
                        _: 'display',
                        sort: 'sort'
                    } 
                },
               { "data": "splits.split_2_NoName", 
                    "render": {
                        _: 'display',
                        sort: 'sort'
                    } 
                },
               { "data": "splits.split_3_Barr Camp", 
                    "render": {
                        _: 'display',
                        sort: 'sort'
                    } 
                },
               { "data": "splits.split_4_A-Frame", 
                    "render": {
                        _: 'display',
                        sort: 'sort'
                    } 
                },
               { "data": "splits.split_5_1 to Go", 
                    "render": {
                        _: 'display',
                        sort: 'sort'
                    } 
                },
               { "data": "segments.segment_Barr Camp", 
                    "render": {
                        _: 'display',
                        sort: 'sort'
                    } 
                },
               { "data": "segments.segment_Barr Camp to Summit", 
                    "render": {
                        _: 'display',
                        sort: 'sort'
                    } 
                },
               { "data": "segments.segment_Treeline to Summit", 
                    "render": {
                        _: 'display',
                        sort: 'sort'
                    } 
                },
               { "data": { 
                    "_": "finish_display",
                    "sort": "finish_sort"}
                },
               { "data": { 
                    "_": "gun_display",
                    "sort": "finish_sort"}
                },
               { "data": "finish_pace" }
            ],
           <more deta tables options>
    

    As part of the DataTables setup, you will also see an fnInitComplete section (I should update this to the newer 1.10.x api syntax)

    <continued from above>
    "fnInitComplete": function () {
    
       // Add event listener for opening and closing details
        $('#results tbody').on('click', 'tr', function () {
            var tr = $(this).closest('tr');
            var row = oTable.row( tr );
     
            if ( row.child.isShown() ) {
                // This row is already open - close it
                row.child.hide();
                tr.removeClass('parent');
            }
            else {
                // Open this row
                row.child( childData(row.data()), 'child' ).show();
                tr.addClass('parent');
            }
        } );
    
    } );
    

    This adds an event listener to catch when folks click on a row. If the child data is already displayed, it closes it. Otherwise, it creates a child row and fills in the row with the result of the childData(row.data()) call.

    The argument to childData is the JSON object used for that row. We need to jump through a few layers of method calls to get to it, hence the 'tr' and 'row' objects. oTable is just the name of the DataTable I created earlier.

    You can replace childData() with an inline function, but it got a bit ugly so I split it out.

    Earlier in the file you will see childData defined (because you need to define the function before you use it.

    function childData ( rData) {
                    
      var data = '<div class="detail">';
      data += '<div class="row">';
      data += '<div class="participant">' // personal
      data += '<div class="part-name">' + rData.full_name + '</div>';
      data += '<div class="part-stats">Bib: ' + rData.bib + '</div>';
      data += '<div class="part-stats">Age: ' + rData.age + '   Sex: ' + rData.sex + '   AG: ' + rData.ag + '</div>';
      data += '<div class="part-stats">' + rData.city + ', ' + rData.state + '</div>';
       data += '</div>'; // personal
    
     
           data += '</div>'; // detail
    
           return data;
       }
    

    (I truncated this for clarity)

    In this function, rData is a pointer to the JSON object that defines the row. We create a string and then start to append html to it as needed based on the data in the JSON object. So the usual json/javascript syntax applies. In the original link you will see references to things like this:

    rData.splits["split_5_1 to Go"].display 
    

    for the cases where I need to get to something that has a space in the name (otherwise I could cheat and do "rData.splits.split_5.display", but in my case I wanted to preserve the name of the split that the user created and that means anticipating spaces.)

    In the chldData function, I can pull all sorts of stuff out, do if-then-else type of things, perform an iteration over a sub-array, etc. But that is beyond the scope of this question.

    The final thing the childData does is return the string.

    The end result is a JSON sourced table that reveals additional details when the row is clicked.

  • cyrillecyrille Posts: 4Questions: 1Answers: 0

    Wow, thank you very much segfaulcoredump, that was exactly what I was looking for.

This discussion has been closed.