3
votes

I'm having trouble with the footerCallback function in the Datatables plugin.

My table lists historical invoices. Users can check a checkbox on each table row that adds the invoice total to a hidden column in the same row.

I'm using the footerCallback function to sum up the values in the hidden column.

The problem is, the footerCallback function is only executing on the initial page load. I need the function to execute after each checkbox check so the sum that will be displayed in the footer updates appropriately.

HTML

<table class="table table-bordered" id="datatable">
<thead>
<tr>
<th>Pay In Full</th>
          <th>Pay This Time</th>
            <th></th>
        </tr>
      </thead>
      <tfoot>
        <tr class="foot">
          <th></th>
          <th class="text-right">
            <h3 class="semibold nm mr5" id="amounttopay">$0.00</h3>
          </th>
            <th></th>
        </tr>
      </tfoot>
      <tbody>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="109.92" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".one" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />109.92
            </div> <span class="one"></span>
          </td>
            <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="6.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />6.65
            </div> <span class="two"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="16.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />16.65
            </div> <span class="two"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="109.92" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".one" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />109.92
            </div> <span class="one"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="6.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>

              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />6.65
            </div> <span class="two"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="16.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />16.65
            </div> <span class="two"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="109.92" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".one" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />109.92
            </div> <span class="one"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="6.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>

              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />6.65
            </div> <span class="two"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="16.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />16.65
            </div> <span class="two"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="109.92" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".one" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />109.92
            </div> <span class="one"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="6.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>

              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />6.65
            </div> <span class="two"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="16.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />16.65
            </div> <span class="two"></span>
          </td>
             <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="109.92" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".one" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />109.92
            </div> <span class="one"></span>
          </td>
          <td class="hidden"></td> 
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="6.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />6.65
            </div> <span class="two"></span>
          </td>
            <td class="hidden"></td>
        </tr>
        <tr>
          <td class="text-center payinfull">
            <input class="payfull" name="SPI_InvPay_Select" type="checkbox" value="16.65" />
          </td>
          <td class="text-center paythistime">
            <div class="input-group"> <span class="input-group-addon">$</span>
              <input class="form-control paynow" data-parsley-error-message="Invalid Character" data-parsley-errors-container=".two" data-parsley-pattern="^\d+(,\d{1,2})?$" type="text" />16.65
            </div> <span class="two"></span>
          </td>
            <td class="hidden"></td>
        </tr>
      </tbody>
    </table>

CSS

.icheckbox_square-blue,
.iradio_square-blue {
  display: inline-block;
  *display: inline;
  vertical-align: middle;
  margin: 0;
  padding: 0;
  width: 22px;
  height: 22px;
  background: url(https://cdnjs.cloudflare.com/ajax/libs/iCheck/1.0.1/skins/square/blue.png) no-repeat;
  border: none;
  cursor: pointer;
}
.icheckbox_square-blue {
  background-position: 0 0;
}
.icheckbox_square-blue.hover {
  background-position: -24px 0;
}
.icheckbox_square-blue.checked {
  background-position: -48px 0;
}
.icheckbox_square-blue.disabled {
  background-position: -72px 0;
  cursor: default;
}
.icheckbox_square-blue.checked.disabled {
  background-position: -96px 0;
}
.iradio_square-blue {
  background-position: -120px 0;
}
.iradio_square-blue.hover {
  background-position: -144px 0;
}
.iradio_square-blue.checked {
  background-position: -168px 0;
}
.iradio_square-blue.disabled {
  background-position: -192px 0;
  cursor: default;
}
.iradio_square-blue.checked.disabled {
  background-position: -216px 0;
}
/* Retina support */

@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
  .icheckbox_square-blue,
  .iradio_square-blue {
    background-image: url([email protected]);
    -webkit-background-size: 240px 24px;
    background-size: 240px 24px;
  }
}

jQuery

function init_icheck() {
    $('#datatable input[type=checkbox]').iCheck({
        checkboxClass: 'icheckbox_square-blue',
        increaseArea: '10%'
    });
}

// When Pay in Full Checkbox is Checked fill in Pay This Time Field with Invoice Amount Due Value
function paynow() {
    var payFull = $('input[type="checkbox"].payfull');
    payFull.on('ifChecked', function(event) {
        $(this).parents('tr').find('.paynow').val($(this).val().replace('$', ''));
        Calc();
    });
}

// If Pay in Full Unchecked then remove value from respective Pay This Time Input
// Only bind the ifUnchecked event if the checkbox is checked
function remove_checkbox() {
    var payFull = $('input[type="checkbox"].payfull');
    payFull.on('ifUnchecked', function(event) {
        if ($(this).parents('tr').find('.paynow').val() == $(this).val().replace('$', '')) {
            $(this).parents('tr').find('.paynow').val('');
            Calc();
        }
    });
}

// If Pay This Time changes recalculate total
function recalc_total() {
    $('.paynow').keyup(function() {
        var $ThisCheck = $(this).parents('tr').find('.payfull');
        // Add Commas if # is over 1,000
        $(this).val(addCommas($(this).val()));
        if ($(this).val() == $ThisCheck.val().replace('$', '')) {
            $ThisCheck.iCheck('check');
        } else {
            $ThisCheck.iCheck('uncheck');
        }
        Calc();
    });
}

// Recalc Function
function Calc() {
    var Sum = 0;
    $('.paynow').each(function(index, Obj) {
        var value = parseFloat($(this).val().replace(',', ''));
        if (!isNaN(value)) Sum += value;
    });
    $('#amounttopay').text('$' + Sum.toFixed(2).replace(/\B(?=(?:\d{3})+(?!\d))/g, ','));
}

// Add Commas if value > 1,000
addCommas = function(input) {
    // If the regex doesn't match, `replace` returns the string unmodified
    return (input.toString()).replace(
        // Each parentheses group (or 'capture') in this regex becomes an argument 
        // to the function; in this case, every argument after 'match'
        /^([-+]?)(0?)(\d+)(.?)(\d+)$/g,
        function(match, sign, zeros, before, decimal, after) {
            // Less obtrusive than adding 'reverse' method on all strings
            var reverseString = function(string) {
                return string.split('').reverse().join('');
            };
            // Insert commas every three characters from the right
            var insertCommas = function(string) {
                // Reverse, because it's easier to do things from the left
                var reversed = reverseString(string);
                // Add commas every three characters
                var reversedWithCommas = reversed.match(/.{1,3}/g).join(',');
                // Reverse again (back to normal)
                return reverseString(reversedWithCommas);
            };
            // If there was no decimal, the last capture grabs the final digit, so
            // we have to put it back together with the 'before' substring
            return sign + (decimal ? insertCommas(before) + decimal + after : insertCommas(before + after));
        }
    );
};

// Calc and update pay this time display
Calc();

// Initialize Datatables
$('#datatable').dataTable({
    "stateSave": true,
    "footerCallback": function(row, data, start, end, display) {
        var api = this.api(),
            data;

        // 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(2).data().length) {
            var total = api.column(2).data().reduce(function(a, b) {
                return intVal(a) + intVal(b);
            })
        } else {
            total = 0
        };

        // Total over this page
        if (api.column(2).data().length) {
            pageTotal = api
                .column(2, {
                    page: 'current'
                })
                .data()
                .reduce(function(a, b) {
                    return intVal(a) + intVal(b);
                })
        } else {
            pageTotal = 0
        };

        // Update footer
        $(api.column(2).footer()).html('$' + total);
        alert(total);
    },

    "oLanguage": {
        "sSearch": "Search Results:"
    },
    "initComplete": function(settings) {
        init_icheck();
        paynow();
        remove_checkbox();
        recalc_total();
    }
});
// Reinitialize iCheck on Pagination Change
$('#datatable').on('draw.dt', function() {
    init_icheck();
    paynow();
    recalc_total();
    remove_checkbox();
});

I've created a Fiddle below:

http://jsfiddle.net/tgf59ezr/

1

1 Answers

6
votes

You need to call draw() API method to redraw the table with false as a first argument to indicate that the page number should be preserved, see below:

$('#datatable').DataTable().draw(false);

Also your code had many issues and could be simplified so that the call above is not even needed.

See updated jsFiddle for code and demonstration.