Getting the total using footerCallback

Getting the total using footerCallback

mRendermRender Posts: 151Questions: 26Answers: 13
edited June 2014 in Free community support

Really simple - but getting stuck and I'm not sure why this is happening.

I'm using footerCallback with the editor and I'm getting the error: Reduce of empty array with no initial value. I'm just trying to add a total to the bottom line using the example staff.php page.

    $('#example').DataTable( {
        dom: "Tfrtip",
        pageLength: -1,
        paging: false,
        info: false,
        ajax: "DataTables-1.10.0/extensions/Editor-1.3.1/examples/php/staff.php",
        columns: [
            { data: null, render: function ( data, type, row ) {
                // Combine the first and last names into a single table field
                return data.first_name+' '+data.last_name;
            } },
            { data: "position" },
            { data: "office" },
            { data: "extn" },
            { data: "start_date" },
            { data: "salary", render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) }
        ],
        "columnDefs": [
            { "visible": true, "targets": 3 }
        ],
        "order": [[ 2, 'asc' ]],
        tableTools: {
            sRowSelect: "os",
            sSwfPath: "../DataTables-1.10.0/extensions/TableTools/swf/copy_csv_xls_pdf.swf",
            aButtons: [
                { sExtends: "editor_create", editor: editor },
                { sExtends: "editor_edit",   editor: editor },
                { sExtends: "editor_remove", editor: editor },
                "print",
                {
                    "sExtends":    "collection",
                    "sButtonText": "Save",
                    "aButtons":    [ "csv", "xls", "pdf" ]}
            ]
        },
          footerCallback: function ( row, data, start, end, display ) {
            var api = this.api();
            // Remove the formatting to get integer data for summation
            var intVal = function ( i ) {
                return typeof i === 'string' ?
                    i.replace(/[\$,]/g, '')*1 :
                    typeof i === 'number' ?
                        i : 0;
            };
 
            // Total over all pages
            var total = api
                .column( 6 )
                .data()
                .reduce( function (a, b) {
                    return intVal(a) + intVal(b);
                } );
 
            // Total over this page
            var pageTotal = api
                .column( 6, { page: 'current'} )
                .data()
                .reduce( function (a, b) {
                    return intVal(a) + intVal(b);
                } );
 
            // Update footer
            $( api.column( 5 ).footer() ).html(
                '$'+pageTotal +' ( $'+ total +' total)'
            );
        }
    } );
} );
<table id="example" class="display" cellspacing="0" width="100%">
    <thead>
        <tr>
            <th>Name</th>
            <th>Position</th>
            <th>Office</th>
            <th>Extn.</th>
            <th>Start date</th>
            <th>Salary</th>
        </tr>
    </thead>

    <tfoot>
    <tr>
                <th colspan="5" style="text-align:right">Total:</th>
                <th></th>
            </tr>
        <tr>
            <th>Name</th>
            <th>Position</th>
            <th>Office</th>
            <th>Extn.</th>
            <th>Start date</th>
            <th>Salary</th>
        </tr>
    </tfoot>
</table>

Website example: http://108.160.144.86/testingeditor.php

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 63,542Questions: 1Answers: 10,476 Site admin
    Answer ✓

    Hi,

    Thanks for the link and the test case. The problem is occurring because the footer callback is being run on the initial draw, before the data is loaded. At that point the data() method is returning an empty array and reduce is not too happy about it. I've reproduced the issue in this little test case: http://live.datatables.net/fenexon/1/edit .

    The fix is to check for data before running the sum calculation: if ( api.column( 6 ).data().length ) { ... }. You could also add an else and output 0 or something else when there is no data, which might be a good idea for filtering. I'll look at updating my column summation example for this!

    Allan

  • mRendermRender Posts: 151Questions: 26Answers: 13
    edited June 2014

    Hi Allan,

    Your brilliance is astounding. I can only hope to be as good as you are one day. Okay, on to the solution that I used for anyone else having issues.

    footerCallback: function ( row, data, start, end, display ) {
                var api = this.api();
                // Remove the formatting to get integer data for summation
                var intVal = function ( i ) {
    
                    return typeof i === 'string' ?
                        i.replace(/[\$,]/g, '')*1 :
                        typeof i === 'number' ?
                            i : 0;
                            
                };
     
                // Total over all pages
    
                    if (api.column(COLNUMBER).data().length){
                    var total = api
                    .column( COLNUMBER )
                    .data()
                    .reduce( function (a, b) {
                    return intVal(a) + intVal(b); 
                    } ) }
                    else{ total = 0};
                    
     
                // Total over this page
                
                if (api.column(COLNUMBER).data().length){
                var pageTotal = api
                    .column( COLNUMBER, { page: 'current'} )
                    .data()
                    .reduce( function (a, b) {
                        return intVal(a) + intVal(b);
                    } ) }
                    else{ pageTotal = 0};
     
                // Update footer
                $( api.column(COLNUMBER).footer() ).html(
                    '$'+pageTotal
                );
            }
    

    Thanks!

This discussion has been closed.