Having trouble with data table responsive and child row.

Having trouble with data table responsive and child row.

bstudentbstudent Posts: 8Questions: 1Answers: 0

I know this similar topic is here a lot, and I've read and tried most examples, but I am unable to get the exact desired result.
summary of what I want: Data table - if row has a 'note'.. display it as a child row, open automatically with no option to close. if note = ''.. then do not display a child row. AND have table be able to show and hide columns based on size but never become a child. 'note' should only ever be the child.

<table id="account_history" class="display table table-bordered table-sm" width="100%">
    <thead>
        <tr class="text-nowrap">
            <th>Date</th>
            <th>Time</th>
            <th>Uder ID</th>
            <th>Code</th>
            <th>Description</th>
            <th>Desk</th>
            <th>Next Rvw.</th>
            <th>Status</th>
            <th class="none">Note</th>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>


<script type="text/javascript">
$(document).ready(function(e){
    
        var base_url = "<?php echo base_url(); ?>";
    var account  = "<?php echo $this->account_number; ?>";

    var table = $('#account_history').DataTable({
        "responsive": {
            details: false,
        },
        "order": [[0, "desc" ]],

        "ajax":{
            url :  base_url+'account/'+account+'/history',
            type : 'POST',
            "dataSrc": function (myJson) {
                if(myJson == "TIMEOUT")
                { window.top.location.href = base_url+'logout'; return; }
                return myJson.data;
            }
        },

        columns: [
            { data: 'date',     name: 'date',       orderable: true },
            { data: 'time',     name: 'time',       orderable: false },
            { data: 'user_id',  name: 'user_id',    orderable: false },
            { data: 'acc_code',   name: 'acc_code', orderable: false },
            { data: 'desc',     name: 'desc',       orderable: false },
            { data: 'desk',     name: 'desk',       orderable: false },
            { data: 'next_rvw',    name: 'next_rvw',    orderable: false },
            { data: 'status',           name: 'status',     orderable: false },

            { data: 'note',     name: 'note',       orderable: false, visable: false }
        ],

    }); //account_history

    $("#account_history").DataTable().rows().every( function () {

        var tr = $(this.node());
                var row = table.row( tr );
        var d = row.data();
        this.child(
                '<div class="table-responsive">'+
                    '<table class="table table-bordered table-sm mb-0">'+
                        '<tr>'+
                            '<td class="border-top-0 p-0">'+d.note+'</td>'+
                        '</tr>'+
                    '</table>'+
                '</div>'
        ).show();
        tr.addClass('shown');
    });

}); // End Document Ready Function
</script>

I have versions working with controls in column 0 using an on click function to open and created row function if (data.note === '') to not display the +/- icon, but i cannot combine all these functions to find my explained effect.
Please help if you can
Thanks
Brian

This question has an accepted answers - jump to answer

Answers

  • colincolin Posts: 15,237Questions: 1Answers: 2,598

    I'm not seeing the test for the note being empty, so suspect something might be missing. As there's a lot going on there, 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

  • bstudentbstudent Posts: 8Questions: 1Answers: 0

    Thank you,
    http://live.datatables.net/morutema/1/edit
    I'm having trouble duplicating it because what i posted in this link is coming back undefined being ajax sourced, because I'm a beginner and my source is server side ajax in this format.."data":[{"date":"2010-05-25","time":"07:57","user_id":"JCH" and i don't know how to fix that for this paste.

    SO, hopefully you know what I mean and i am trying to accomplish?
    in the link above forget about the controls for all items and "undefined" when triggered for a moment, because i have that part working.. only when there is a note do you get the controls to open.

    BUT what I am looking for is how to get rid of controls column, open child of row only if there is a note so there is no blank child row ( you can see the test for if (data.note === '') ), and still keep the column visibility of all, desktop, etc..

    Brian

  • kthorngrenkthorngren Posts: 21,166Questions: 26Answers: 4,921
    edited December 2019

    my source is server side ajax in this format.."data":[{"date":"2010-05-25","time":"07:57","user_id":"JCH" and i don't know how to fix that for this paste.

    One option is to use the browser's Developer Tools > Network to look at the Ajax (XHR) response. You can copy the response to use in the test case. This technote provides steps to find the XHR response. Or you can simply just create dummy data that matches your data structure.

    coming back undefined being ajax sourced

    In your code you are using object defined by columns.data. But in your test case you are using arrays and trying to get the note with data.note. That notation won't work with arrays.

    you can see the test for if (data.note === ''

    The same answer as above with using arrays instead of objects in the test case.

    I'm confused with what you really want. In the first post you mention you want to show all child rows that have notes with data. You also have a loop that looks like it might do this - except for checking if data.notes === ''.

    But your test case is showing the details-control column and you are trying to eliminate the plus if notes is empty. Down't sound like this is what you want.

    I will assume that what you are really after is your first post with showing all child rows with notes that contain data when the table loads. I haven't tried your code that loops all the rows to show the child rows but it looks like it should work. There are two problems that standout:

    1. You need to check for data.notes === '' inside the loop.
    2. You need to move the loop inside initComplete due to using Ajax. Ajax is an async operation and the loop, as it is, will execute before the Ajax response and Datatables initialization.

    Here are my suggested changes:

        var table = $('#account_history').DataTable({
            "responsive": {
                details: false,
            },
            "order": [[0, "desc" ]],
     
            "ajax":{
                url :  base_url+'account/'+account+'/history',
                type : 'POST',
                "dataSrc": function (myJson) {
                    if(myJson == "TIMEOUT")
                    { window.top.location.href = base_url+'logout'; return; }
                    return myJson.data;
                }
            },
     
            columns: [
                { data: 'date',     name: 'date',       orderable: true },
                { data: 'time',     name: 'time',       orderable: false },
                { data: 'user_id',  name: 'user_id',    orderable: false },
                { data: 'acc_code',   name: 'acc_code', orderable: false },
                { data: 'desc',     name: 'desc',       orderable: false },
                { data: 'desk',     name: 'desk',       orderable: false },
                { data: 'next_rvw',    name: 'next_rvw',    orderable: false },
                { data: 'status',           name: 'status',     orderable: false },
     
                { data: 'note',     name: 'note',       orderable: false, visable: false }
            ],
    
            initComplete: function () {
                this.api().rows().every( function () {
                    var d = row.data();
     
                    if ( d.note !== '' ) { .  // Skip if note is blank
                           var tr = $(this.node());
                           var row = table.row( tr );
                           var d = row.data();
                           this.child(
                                   '<div class="table-responsive">'+
                                       '<table class="table table-bordered table-sm mb-0">'+
                                           '<tr>'+
                                               '<td class="border-top-0 p-0">'+d.note+'</td>'+
                                           '</tr>'+
                                       '</table>'+
                                   '</div>'
                           ).show();
                           tr.addClass('shown');
                      }
                });
            }
     
        }); //account_history
    

    If this doesn't help then please update your test case to use an example of your object data and the child code you want to use.

    Kevin

  • bstudentbstudent Posts: 8Questions: 1Answers: 0

    OK, I will try the initComplete as soon as possible. I think that might be it.
    Thanks for your quick reply, and I will get back with my results

  • bstudentbstudent Posts: 8Questions: 1Answers: 0

    OK.
    I was able to update the test case:
    http://live.datatables.net/morutema/2/edit
    You can see that if there is a note you get the option to open the child.
    But, what I want is to eliminate the controls column, and have child rows open always (but only if there is a note - we want no blank rows), BUT still keep the column visibility options (all, desktop, tablet) on resizing so the note is the only child that would ever be created.

    after trying the initComplete I am getting:

    0003335830:294 Uncaught TypeError: Cannot read property 'data' of undefined
        at _Api.<anonymous> (0003335830:294)
        at _Api.<anonymous> (jquery.dataTables.js:9451)
        at _Api.iterator (jquery.dataTables.js:7059)
        at _Api.<anonymous> (jquery.dataTables.js:9440)
        at _Api.every (jquery.dataTables.js:7196)
        at w.fn.init.initComplete (0003335830:293)
        at jquery.dataTables.js:6638
        at Function.map (jquery-3.3.1.min.js:2)
        at _fnCallbackFire (jquery.dataTables.js:6637)
        at _fnInitComplete (jquery.dataTables.js:4786)
    
  • bstudentbstudent Posts: 8Questions: 1Answers: 0
    Uncaught ReferenceError: row is not defined
        at _Api.<anonymous> (0003335830:364)
        at _Api.<anonymous> (jquery.dataTables.js:9451)
        at _Api.iterator (jquery.dataTables.js:7059)
        at _Api.<anonymous> (jquery.dataTables.js:9440)
        at _Api.every (jquery.dataTables.js:7196)
        at w.fn.init.initComplete (0003335830:363)
        at jquery.dataTables.js:6638
        at Function.map (jquery-3.3.1.min.js:2)
        at _fnCallbackFire (jquery.dataTables.js:6637)
        at _fnInitComplete (jquery.dataTables.js:4786)
    
  • kthorngrenkthorngren Posts: 21,166Questions: 26Answers: 4,921

    The rows().every() loop needed a few changes:
    http://live.datatables.net/gejihihi/1/edit

    BTW, the table formatting is not correct. Likely due to not having bootstrap.css installed.

    Kevin

  • bstudentbstudent Posts: 8Questions: 1Answers: 0

    I got this working now!!!
    it is the initComplete. just changed a little bit to:

            initComplete: function () {
                this.api().rows().every( function () {
                    var tr = $(this.node());
                    var row = table.row( tr );
                    var d = row.data();
    
                    if ( d.note !== '' ) {
                           this.child(
                                   '<div class="table-responsive">'+
                                       '<table class="table table-bordered table-sm mb-0">'+
                                           '<tr>'+
                                               '<td class="border-top-0 p-0">'+d.note+'</td>'+
                                           '</tr>'+
                                       '</table>'+
                                   '</div>'
                           ).show();
                           tr.addClass('shown');
                      }
                });
            },
    

    Thanks everyone!

  • bstudentbstudent Posts: 8Questions: 1Answers: 0

    I stand corrected. Now new related problem
    It is not working on subsequent pages ( because initComplete does not run again?). Only on first load of page.

  • kthorngrenkthorngren Posts: 21,166Questions: 26Answers: 4,921
    Answer ✓

    The example I provide does work on subsequent pages. I updated one of the notes on page 2 in this example:
    http://live.datatables.net/gejihihi/2/edit

    I could see it not working if you were using serverSide or deferRender but I don't see either in any of the code you posted.

    If initComplete doesn't work for you then you should be able to use rowCallback. Its a callback for each row drawn so you wouldn't need the rows().every(). Here is the changed example to use rowCallback:
    http://live.datatables.net/xupevedo/1/edit

    Kevin

  • bstudentbstudent Posts: 8Questions: 1Answers: 0

    kthorngren,
    Thank you very much! Very quick and helpful
    Yes it is serverSide, and rowCallback is working as I would like
    Brian

This discussion has been closed.