How to print child rows

How to print child rows

bignidesbignides Posts: 5Questions: 2Answers: 0

This question has been asked a number of times and I needed it done so I wanted to post my solution.
Things to note:
1) I created this rather quickly for an express purpose to meet my needs:
a) Child rows had their own DataTables, originally
b) Child rows now can have a small amount of html which is not properly scrubbed
2) There is code in here you probably don't need, like my specific classes
3) Excuse the weird formatting
4) I'm not the best JS programmer so bear with me

OK, on to the code:

First, you need to add an index column, so in your initialization use this as your first column:

columns: [
    {
            /*
             * column exists for purpose of printing/exporting
             * only required when using child rows
             */
            title   : 'index'
          , visible : false
          , render  : function( row, type, full, meta ) {
                return meta.row;
          }
    },

Next, you need to add the print button to your DataTable:

buttons : [
{
        extend : 'print'
      , action : function( e, dt, button, config ) {
            dt_print( e, dt, button, config, true )
      } /* true here means table has child rows */
}

Leaving out the extra true allows you to use the code on datatables without child rows or child rows you don't care to print.

Lastly, you need to modify the original print button code from http://github.com/DataTables/Buttons/blob/master/js/buttons.print.js
I took all the required variables from there and replaced the action function of DataTable.ext.buttons.print to the following:

function dt_print( e, dt, button, config, has_child_rows ) {
    var data = dt.buttons.exportData( config.exportOptions );
    var addRow = function ( d, tag, child_row ) {
        var str = '<tr>';

        for ( var i = 0, ien = d.length; i < ien; i++ ) {
            if (has_child_rows && ! child_row && i === 0) continue;
            str += '<' + tag + '>' + d[i] + '</' + tag + '>';
        }

        return str + '</tr>';
    };

    var addSubTable = function ( subtable, colspan ) {
        var str = '<tr class="innertable-row">'
                +     '<td class="innertable-row" colspan="' + colspan + '">';

        // If there is no subtable, there must be other child row content, display that
        if ( subtable.length == 0 ) {
            str += '<div style="text-align: left">'
            str += $( dt.row( row_idx ).child() ).children().children().html();
            return str + '<div></td></tr>';
        }

        // Add header row
        var headers = subtable.find('tr').first().find('th,td');

        str += '<table class="dataTable no-footer">'
            +    '<thead><tr>';

        for ( var i = 0; i < headers.length; i++ ) {
            str += '<th>' + headers.eq(i).text() + '</th>';
        }

        str += '</tr></thead><tbody>';

        // Add body rows
        subtable.find('tbody').children('tr').each(function(index, tr) {
            var lines = $('td', tr).map(function(index, td) {
                return $(td).text();
            });
            str += addRow( lines, 'td', true );
        });

        return str + '</tbody></table></td></tr>';
    };

    // Construct a table for printing
    var html = '<table class="' + dt.table().node().className + '">';

    if ( config.header ) {
        html += '<thead>' + addRow( data.header, 'th' ) + '</thead>';
    }

    html += '<tbody>';
    for ( var i = 0, ien = data.body.length; i < ien; i++ ) {
        html += addRow( data.body[i], 'td' );

        if ( has_child_rows ) {
            var row_idx = data.body[i][0];
            if ( dt.row( row_idx ).child() && dt.row( row_idx ).child.isShown() ) {
                html += addSubTable( $( dt.row( row_idx ).child() ).find( 'table:visible' ), data.body[0].length );
            }
        }
    }
    html += '</tbody>';

    if ( config.footer && data.footer ) {
        html += '<tfoot>' + addRow( data.footer, 'th' ) +'</tfoot>';
    }

    // Open a new window for the printable table
    var win = window.open();
    var title = config.title;

    if ( typeof title === 'function' ) {
        title = title();
    }

    if ( title.indexOf( '*' ) !== -1 ) {
        title = title.replace( '*', $('title').text() );
    }

    win.document.close();

    // Inject the title and also a copy of the style and link tags from this
    // document so the table can retain its base styling. Note that we have
    // to use string manipulation as IE won't allow elements to be created
    // in the host document and then appended to the new window.
    var head = '<title>'+title+'</title>';
    $('style, link').each( function() {
        head += _styleToAbs( this );
    });

    try {
        win.document.head.innerHTML = head; // Work around for Edge
    }
    catch (e) {
        $( win.document.head ).html( head ); // Old IE
    }


    // Inject the table and other surrounding information
    win.document.body.innerHTML =
          '<h1>' + title + '</h1>'
        + '<div>'
        +    (typeof config.message === 'function' ?
                config.message( dt, button, config ) :
                config.message
            )
        + '</div>'
        + html;


    $( win.document.body ).addClass('dt-print-view');

    $('img', win.document.body).each( function ( i, img ) {
        img.setAttribute( 'src', _relToAbs( img.getAttribute('src') ));
    });

    if ( config.customize ) {
        config.customize( win );
    }

    setTimeout( function() {
        if ( config.autoPrint ) {
            win.print();
            win.close();
        }
    }, 250 );
}

If you know how to do this better or cleaner, I'd love to hear it.

Answers

  • josivanljosivanl Posts: 11Questions: 3Answers: 1

    Helped me greatly your post!

    It works perfectly

    Thank you

  • haithamshahaithamsha Posts: 1Questions: 0Answers: 0

    Could you provide the full example, I tried but not worked.

  • MaycoMayco Posts: 2Questions: 0Answers: 0

    Hi Bignides.
    I am not able use your solution, May you help me?

    When I click on print button I get a error:

    script.js:90 Uncaught ReferenceError: dt_print is not defined
    at s.action (script.js:90)
    at q (dataTables.buttons.min.js:13)
    at HTMLButtonElement.<anonymous> (dataTables.buttons.min.js:14)
    at HTMLButtonElement.dispatch (jquery-3.2.1.js:5206)
    at HTMLButtonElement.elemData.handle (jquery-3.2.1.js:5014)

  • JSPróJSPró Posts: 4Questions: 2Answers: 0

    Could you provide the full example, I tried but not worked.

Sign In or Register to comment.