Add Normalized Child Rows during rowCreated?

Add Normalized Child Rows during rowCreated?

joshuasiegaljoshuasiegal Posts: 19Questions: 2Answers: 1
edited September 2015 in Free community support

Hey, I have a project I'm working on where user data is returned from a service and each user has multiple nested profiles. I'm trying to add multiple child rows to each user row, changing profile-specific data for each child row.

Here is what I'm trying:

userAccountsDTO = $userAccountsTable.DataTable({
    data:theData,
    columns:userAccountsMap,
    createdRow:function(row, data, index) {
        if (data.profiles.length) {
            //normalize data for child rows here, but for now
            //just test child row insertion with dummy string:
            row.child("Heyyyy");
        }
    }
});  

This isn't working - I'm guessing that 'row' here isn't the same as elsewhere in the documentation for example row.child().

What is the proper way to do this?

Much thanks!

This question has an accepted answers - jump to answer

Answers

  • ThomDThomD Posts: 334Questions: 11Answers: 43

    A row is a row is a row. Or something like that.

    row.child( ) takes an argument that is the function you write. That function returns whatever you need to display in the child.

    You must get the row.data to send to your function. I have an on click event on an image, so I use this to get the full row data and invoke the child.

    ('#myTable img.details-control').on('click', '', function () {
        var tr = $(this).closest('tr');
        var row = dtTable.row( tr );
        row.child( formatChild(row.data()) ).show();
    }
    ....
    

    So, I have formatChild() like this

    function formatChild ( rowData ) {
        
        [Build an HTML Table that holds what I need with some complex logic, also with a placeholder div]
    
        var ModifiedbyName = "";
        var ModNameURI = rowData.ModifiedBy.__deferred.uri;
        if ( varModURI !== '' ) {
            $.getJSON(varModNameURI,
                function (data) {
                    ModifiedbyName = data.d.Name;
                    $("#ModifiedByPlaceHolder").text(ModifiedbyName);
                }
            );  
        }
    
        return smallTable;
    
    
    
    }   
    

    This function builds a table and makes an Ajax call to get a value that goes into the placeholder div.

  • joshuasiegaljoshuasiegal Posts: 19Questions: 2Answers: 1

    Hey ThomD, thanks so much for the reply. I think that my question - in your example - would boil down to this:

    How do I call the row method:

     var row = dtTable.row( tr );
    

    from within the createdRow method? I'm guessing your dtTable is analogous to my userAccountsDTO. But how does that show up within the createdRow method?

  • ThomDThomD Posts: 334Questions: 11Answers: 43

    If you wanted the children to always show, then either you would add this to createdRow:

    createdRow: function (row, data, rowIndex) { 
         row.child( formatMyChild(data) ).show();
    }
    

    where formatMyChild() is a function that returns whatever HTML you want to show.

    The other (I suspect better) way is to do that as part of InitComplete or table.draw() - loop through each row and make that call.

  • joshuasiegaljoshuasiegal Posts: 19Questions: 2Answers: 1

    Hey ThomD,

    Thanks again for replying - but w/in the context of 'createdRow', the 'row' object just refers to the DOM node (<tr>) - it doesn't have the child() method attached to it - that's my original issue.

    I don't want to do what I'm trying to do InitComplete or table.draw, b/c createdRow gives me the current data context - I don't want to have to loop back through the table and re-map all the data to what just got rendered, that seems to be very inefficient.

  • ThomDThomD Posts: 334Questions: 11Answers: 43

    Well look at that. You are right, child() doesn't exist in the context of created row. If it were me, I'd get it to work by looping through table.rows() and wait to see if Alan offers a better solution. I'm guessing that you may be out of luck because child().show is a rendering function, but createdRow() fires off way before rendering happens.

    Don't worry, the CPU cycles are paid for, so it is OK to use them.

  • joshuasiegaljoshuasiegal Posts: 19Questions: 2Answers: 1
    edited September 2015

    Is there any way to add child rows without having to go back through a previously inittied & created table and shim them in?

    It would seem that for cases like this, it would be a pretty common thing to want to do - for example, if we had data like:

    {
      id:123,
      make:'Subaru',
      origin_country:'Japan',
      models: [
        'Forester',
        'Impreza',
        'Outback'
      ]
    }
    

    That we would want to see data like:

    | Subaru | Japan | Forester |

    | Subaru | Japan | Impreza |

    | Subaru | Japan | Outback |

    With the second and third of these being children of the first, for filtering / sorting purposes. I also think this isn't really a case for Row Grouping, b/c the child-row differences are more granular, not really categorizing the parents.

  • allanallan Posts: 63,252Questions: 1Answers: 10,420 Site admin

    Hi,

    Thanks for the question and the details - fantastic!

    The key thing here is to know that the createdRow function is called in the context of the table that it is being run on - i.e. this is a jQuery object for the table. DataTables adds a method called api() to that object to let you access the DataTables API - so you can do:

    createdRow: function ( row, data, index ) {
      var api = this.api();
      ...
    }
    

    Now you have access to be able to use row().child() and all its friends. So to show the child row it simply becomes: api.row( row ).child( ... )....

    I've put a little example of that together.

    Now where it starts to get a little bit interesting is your array of data that you want to show. Passing an array into the child rows is simple - just pass the array that you want to see in the child rows into the row().child() method - example.

    However, this isn't exactly what you want from the above description and in fact that layout really isn't something that the child rows are suitable for. The child rows will not be taken account of when sorting and filtering unless their data is in the host row - and even then, they still won't be ordered as expected - the child rows are effectively independent of the host table, their only attachement is that the come immediately after the host row in the DOM.

    If you want that layout for the table, then you will need to consider a different option from the child rows which is to normalise the source data - I've put an example of that together as well.

    Hopefully this is some food for thought and you can let me know what you think and how you would like to proceed.

    Regards,
    Allan

  • joshuasiegaljoshuasiegal Posts: 19Questions: 2Answers: 1
    Answer ✓

    This proved to be the solution...I think!

    http://live.datatables.net/samezucu/13/edit

This discussion has been closed.