Add 2nd line to row - similar to .child()

Add 2nd line to row - similar to .child()

typhontyphon Posts: 25Questions: 7Answers: 0

Hello,

is it possible to add a 2nd line with information to a row?

Thx for reply!

This question has accepted answers - jump to:

Answers

  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin
    Answer ✓

    The only option at the moment for that is to use the child rows that you mentioned in the title. You could have the child row always shown with no option to remove it, which might do what you need.

    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0

    Thx for reply. I use MVC with Razor and have a List contains my Data-Objects. Do I've to call in every loop the jquery to add the child or is there a better way?

    Pseudo code:

    foreach(var item in MyDataList) {

    <tr>
    <td> item.Name</<td>

    //Code to add the child....

    </tr>

    }

  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin

    Do I've to call in every loop the jquery to add the child

    Yes basically. row().every() could be used, which is basically an anonymous function loop.

    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0
    edited December 2016

    Thx, but I can't get working it.. How I add the right Object (notes ) to the correct row?

    My fist approach was to add the child to the row inside the loop but I don't know how I call the javascript to get the correct row to add the child?

    Code:

    @foreach(var item in MyItems)
    {
      <table id="example" class="table">
                    <thead>
                        <tr>
                            <th>@Resources.Name</th>
                            <th>@Resources.Subject</th>
                       </tr>
                    </thead>
                     <tbody>
                          @foreach (var item in Model)
                           {
                                 <tr>
                                     <th>@item.Name</th>
                                     <th>@item.Subject</th>
                                     <th>//I've to call the script here because it is not allowed to call the 
                                            //script inside the <table> or <tr> ...
                                      </th>
                                 </tr>
                           }
                    </tbody>  
    }
    

    My second approch:

    var table = $('#example').DataTable();
    
        table.rows().every(function () {
            this
                .child(
                    $(
                        '<tr>' +
                            '<td colspan="2">/* HOW I  Iterate my MyData and append to the correct row? */</td>' +
                        '</tr>'
                    )
                )
                .show();
                
        });
    
    

    Thx a lot for helping me out!

  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin

    The way I'd recommend doing it is to have the information you want to be shown in the child row included in columns in the parent row (i.e. a single row output by your foreach). Then use columns.visible to hide the columns you want to show in the child row.

    Finally use row().child() to create the child row and row().child().show() to show it.

    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0
    edited December 2016

    Hello, thx for reply. I'm sorry but I don't understand your approach. Maybe you have a code snipped for me.

    My approch wich doesn't work :-(

     <td>
        @item.SomeText
    
         <script type="text/javascript">
              var tr = $(this).closest('tr');
              var row = table.row(tr);
              row.child($(
                 '<tr>' +
                 '<td>test</td>' +
                 '</tr>'
              )).show();
              tr.addClass('shown');
           </script>
      </td>
    
  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin

    Hi,

    If we take a basic DataTable as an example: http://live.datatables.net/qeciwuqo/1/edit , you will be able to see in its basic state there that there are six columns, with a single row of data for each record.

    Now if we modify that example ( http://live.datatables.net/qeciwuqo/2/edit ) so that we hide the last three columns, and have their data points shown as child rows, that is basically what I was trying to convoy.

    Does that match what you are looking for (hopefully I've understood what you require correctly!)?

    The key thing here is to keep in mind that you control what is shown in the child row. I've selected in this case to just have the three data points shown without any extra information or formatting about them. You could easily use a ul/li list if required, or any other HTML format you want.

    Regards,
    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0
    edited January 2017

    Hello Allan,thx for response. I'm very close to solve the problem.

    But hiding the columns are not working with your approach.
    This works:

    ('#example').DataTable().column( 0 ).visible( false )
    

    Heres my javascript:

     $('#example').DataTable({
                "order": [[3, "asc"]],
                "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],
                "pageLength": 20,
                stateSave: true,
                stateSaveCallback: function (settings, data) {
                    localStorage.setItem('DataTables_' + settings.sInstance, JSON.stringify(data))
                },
                stateLoadCallback: function (settings) {
                    return JSON.parse(localStorage.getItem('DataTables_' + settings.sInstance))
                },
                "language": {
                    "decimal": "",
                    "emptyTable": "No data available in table",
                    "info": "Showing _START_ to _END_ of _TOTAL_ entries",
                    "infoEmpty": "Showing 0 to 0 of 0 entries",
                    "infoFiltered": "(filtered from _MAX_ total entries)",
                    "infoPostFix": "",
                    "thousands": ",",
                    "lengthMenu": "Show _MENU_ entries",
                    "loadingRecords": "Loading...",
                    "processing": "Processing...",
                    "search": "Search:",
                    "zeroRecords": "No matching records found",
                    "paginate": {
                        "first": "First",
                        "last": "Last",
                        "next": "Next",
                        "previous": "Previous"
                    },
                    "aria": {
                        "sortAscending": ": activate to sort column ascending",
                        "sortDescending": ": activate to sort column descending"
                    }
                },
                columnDefs: [
                   {
                       visible: false,
                       targets: [12]
                   }
                ],
                drawCallback: function () {
                    var api = this.api();
    
                    api.rows({ page: "current" }).every(function () {
                        var rowData = this.data();
    
                        this
                          .child($(
                            '<tr>' +
                              '<td></td><td colspan="10">' + rowData[12] + '</td>' +
                            '</tr>'
                          ))
                          .show();
                    });
                }
            });
    

    And a second problem is that I'm using different row background colors. Is it possible to use the css from the parent row for the child row?

    <tr class="@(item.NewInToDoList ? "danger" : item.OutFromToDoList ? "info" : item.RejectedFromToDoList ? "success" : "")">
    
    .......
    
    </tr>
    
  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin

    But hiding the columns are not working with your approach.

    I see you have state saving enabled. If you had state saving enabled before you adding the columns.visible option, it will have saved the columns visible state as visible! That will override what is set in the options (since it is restoring the state). You could clear the localStorage for your page to check if that is the case here.

    And a second problem is that I'm using different row background colors. Is it possible to use the css from the parent row for the child row?

    Yes - absolutely. This is how it might be done with the loop counter: http://live.datatables.net/qeciwuqo/3/edit .

    Regards,
    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0

    Thx for reply.

    @1 hiding columns: you're right, remove the state save solved the issue.

    @2 child row background colors: I'm using different colors -> bootstrap class danger, success, e.g. .. Is it possible to take the class from the parent row? (each row is a task, you can send a task to another user --> appears blue, if you receive a task it appears blue, if you hold the task the rows are striped -> even, odd).

  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin

    Yes indeed: http://live.datatables.net/qeciwuqo/4/edit .

    I didn't do that before as it is slightly less efficient (need to read the value from the DOM), but you are right, it is far more flexible.

    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0

    Hello,

    thx it works nearly perfect. The table-striped class from bootstrap dont works correct (or it works correct but I want another style ;-)).. There are 3 parent rows with 3 child rows. The first is like expected then the backgroundcolor repeats every row but I want to display the parent and child row in the same background color.

    In this expamle:

    2 rows blue (parent & child)
    2 rows white (parent & child)
    2 rows gray (parent & child)

    This is the html output:

    <tr class="odd" role="row">
         <td>...</td>
         <td>...</td>
         <td class="sorting_1">...</td>
         <td class="">...</td>
         <td>05.03.2015, 06:07</td>
         <td>...</td>
         <td>...</td>
          <td>-</td>
         <td>
           <button id="workflowBtn" class="btn btn-success workflow btn-padding" data-id="37005"><span class="glyphicon glyphicon-transfer" aria-hidden="true">  </span></button>
         </td>
         <td>
           <a class="btn btn-default" target="_blank" href="http://..."><span class="glyphicon glyphicon-tags" aria-hidden="true"></span></a>
         </td>
         <td>
           <a class="btn btn-default" target="_blank" href="....."><span class="glyphicon glyphicon-book" aria-hidden="true"></span></a>
         </td>
         <td>
           <a class="btn btn-info" href="/Task/ShowTask/37005"><span class="glyphicon glyphicon-search" aria-hidden="true"></span> Details</a>
         </td>
                                
         </tr>
    <tr class="odd"><td></td><td colspan="11">....</td></tr>
    

    My javascript:

    $('#example').DataTable({
                "order": [[3, "asc"]],
                "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],
                "pageLength": 25,
                stateSave: true,
                stateSaveCallback: function (settings, data) {
                    localStorage.setItem('DataTables_' + settings.sInstance, JSON.stringify(data))
                },
                stateLoadCallback: function (settings) {
                    return JSON.parse(localStorage.getItem('DataTables_' + settings.sInstance))
                },
                "language": {
                    "decimal": "",
                    "emptyTable": "No data available in table",
                    "info": "Showing _START_ to _END_ of _TOTAL_ entries",
                    "infoEmpty": "Showing 0 to 0 of 0 entries",
                    "infoFiltered": "(filtered from _MAX_ total entries)",
                    "infoPostFix": "",
                    "thousands": ",",
                    "lengthMenu": "Show _MENU_ entries",
                    "loadingRecords": "Loading...",
                    "processing": "Processing...",
                    "search": "Search:",
                    "zeroRecords": "No matching records found",
                    "paginate": {
                        "first": "First",
                        "last": "Last",
                        "next": "Next",
                        "previous": "Previous"
                    },
                    "aria": {
                        "sortAscending": ": activate to sort column ascending",
                        "sortDescending": ": activate to sort column descending"
                    }
                },
                columnDefs: [
                   {
                       targets: [12],
                       visible: false
                   }
                ],
                drawCallback: function () {
                    var api = this.api();
    
                    api.rows({ page: "current" }).every(function (idx, t, i) {
                        var rowData = this.data();
                        if (rowData[12].length > 0) {
                            this
                              .child($(
                                '<tr class="' + (this.node().className) + '">' +
                                  '<td></td><td colspan="11">' + rowData[12] + '</td>' +
                                '</tr>'
                              ))
                              .show();
                        }
                    });
                }
            });
    

    And btw is there a option to remove the border between parent and child row?

    Thx a lot br
    Nicolai

  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin

    And btw is there a option to remove the border between parent and child row?

    Yes - a little CSS will do that: http://live.datatables.net/qeciwuqo/5/edit .

    Regarding the first part of your question. I'm afraid I don't quite understand stand the question. Could you possibly rephrase it?

    Thanks,
    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0
    edited January 2017

    Thx for reply,

    as you see in the screenshot.png the first two rows are blue (as expected). The 3rd row is white the 4th is grey 5th is white and so on.. (table-striped). But the 3rd row is the parent row and the 4th row is the child row from the 3rd. I want to use the same background color.

    In this example:

    1st+2nd row blue
    3rd+4th row white
    5th+6th row gray

    The class is correct for the parent and child rows (odd, even) but I don't know why the background color is different?

    As a possible solution could I take the style from the parent row like the class (this.node().className) and give it to the child row?

    Parent row:

    <tr class="@(item.NewInToDoList ? "danger" : item.OutFromToDoList ? "info" : item.RejectedToDoList ? "success" : "")" style="background: @(i%2 == 0 ? "white" : "f9f9f9")">
    .....
    </tr>
    

    Javascript to add a child row:

    this.child($(
                                '<tr class="' + (this.node().className) + '">' +
                                  '<td style="border-top: none !important; /* ... CODE TO ADD THE BACKGROUND FROM THE PARENT ROW ... */"></td><td colspan="100" style="border-top: none !important;">' + rowData[0] + '</td>' +
                                '</tr>'
                              )).show();
    

    But for sure it would be nice if the even and odd class gives the background color.

    Thx a lot for your patience!

  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin

    It sounds like there must be a style on your page which is giving the cell a colour. A cell background colour sits in front of the row's background, which would explain what you are seeing.

    If you right click on one of the cells that is showing the problem and then select "Inspect" it will show you what styles are being applied to the cell, and hopefully let you identify what CSS needs to be modified on your page.

    Regards,
    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0
    edited January 2017

    I'm using bootstrap.

    .table-striped > tbody > tr:nth-of-type(odd) {
        background-color: #f9f9f9;
    }
    
    

    This css get colored <tr>'s .. I think bootstrap counts child rows like parent rows and so it alternate over all rows..

    If I remove the table-striped class from the table and add this to my css it works like expected:

    .odd {
        background-color: #f9f9f9;
    }
    
    .even {
        background-color: white;
    }
    
    
  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin
    Answer ✓

    I think bootstrap counts child rows like parent rows and so it alternate over all rows..

    It does yes.

    If I remove the table-striped class from the table and add this to my css it works like expected

    Fantastic. Good to hear you've got it working now.

    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0
    edited January 2017

    Hello again, a new question.

    When I use the paging buttons at the bottom the page jumps in the "middle of the page". If I remove the child rows it works correct -> after paging it page shows the paging buttons.

    So I think it doen't calculate the child rows to the jump point?!
    thx and br

    PS: The same problem exists in the child row example: https://datatables.net/examples/api/row_details.html -> if I expand all rows and change the page it jumps somewhere. It would be nice if the paging menu is focused

  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin
    Answer ✓

    If you want DataTables to jump to the top of the page when the user triggers paging, you can use:

            table.on('page', function() {
                setTimeout(function() {
                    $(document).scrollTop($(table.table().container()).offset().top);
                }, 10);
            });
    

    where table is the DataTable instance in question.

    Think that will be a good topic for a blog post :smile:.

    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0

    And to keep the focus on the paging menu @ the bottom?

  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin

    The problem is that the height of the table is changing, so to keep the table footer in the same relative position you'd need to get the position of the footer on the page before the draw, and then alter the scrolling position after the draw and the new table height has been generated.

    Allan

  • typhontyphon Posts: 25Questions: 7Answers: 0

    Here is my final result if somebody need it.

    First of all I hide the div contains the table (display: none) because if I load the view the user see the "unformated" tables for 1-2 seconds.

    Then I apply the time format for sorting (eg: '29.02.2017, 13:40' <- de timeformat)

    After that I init all tables (my view has multible tables). I'm hide the fist col and add this to the chiild row. Finally I add the function that it displays the tables header if I using the paging button.

    Then I hide or show cols with user defined settings:

    tmp = '@ViewBag.ShowRemindDate'.toLowerCase() == 'true' ? true : false;
            $('table.display').each(function () { $(this).DataTable().column(5).visible(tmp) });
    

    Finally I show the div ( $('#toDoFieldSet').show(); ) and I adjust the cols ( table.columns.adjust().draw();).

    $.fn.dataTable.moment('L, LT', '@System.Web.HttpContext.Current.Session["CurrentCulture"]');
    
            var table = $('table.display').DataTable({
                "order": [[4, "asc"]],
                "lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, '@Resources.DataTablesAll']],
                "pageLength": 100,
                stateSave: true,
               columnDefs: [
                   {
                       targets: [0],
                       visible: false,
                   }
                ],
                drawCallback: function () {
                    var api = this.api();
                    api.rows({ page: "current" }).every(function (idx, t, i) {
                        var rowData = this.data();
                        if (rowData[0] != null && rowData[0].length > 0 && '@ViewBag.ShowNotes'.toLowerCase() == 'true') {
                            this.child($(
                                '<tr id="' + this.node().id + '_c" class="' + (this.node().className) + '">' +
                                  '<td style="border-top: none !important;"></td><td colspan="100" style="border-top: none !important;">' + rowData[0] + '</td>' +
                                '</tr>'
                              )).show();
                        }
    
                        this.on('page', function () {
                            setTimeout(function () {
                                $(document).scrollTop($(api.table().container()).offset().top);
                            }, 10);
                        });
                    });
                }
            });
    

    Sometimes it is a topic to maintain the scroll position. I did it with this way:


    $(document).scroll(function () { localStorage['_TaskFeed'] = document.URL; localStorage['scrollTop'] = $(document).scrollTop(); });

    And in document ready AFTER .show():

    if (localStorage['_TaskFeed'] == document.URL) {
                $(document).scrollTop(localStorage['scrollTop']);
            }
    

    So this takes me some work days to put it together.

  • allanallan Posts: 61,686Questions: 1Answers: 10,100 Site admin

    Awesome - thanks for sharing your final solution with us!

    Allan

This discussion has been closed.