0

I am trying to dynamically calculate the line totals and grand totals. I have used this amazing example jquery table rows line totals and grand total as a foundation and have altered the code where necessary to suit my project however, i am running it on my localhost to see if it works and it doesn't seem to be calculating any of the totals and the add/remove buttons don't seem to be working either and i can't figure out why that is? Running the original code works but not my modified version.

http://jsfiddle.net/9gqdq/

HTML:

<table border="0" id="invoiceitems">
    <thead>
        <tr>
            <td></td>
            <td><strong>Paper</strong>
            </td>
            <td><strong>Price</strong>
            </td>
            <td><strong>Per Pack</strong>
            </td>
            <td><strong>Quantity</strong>
            </td>
            <td><strong>Total</strong>
            </td>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <td></td>
            <td></td>
            <td></td>
            <td><strong>Total:</strong>
            </td>
            <td>
                <label class="grandtotal"></label>
            </td>
        </tr>
    </tfoot>
    <tbody>
        <tr>
            <td>
                <input type="button" class="buttondelete" value="Delete" />
            </td>
            <td>
                <input type="text" name="item['. 1 .'][paper]" class="regular-text" value="Glossy   Paper A5" />
            </td>
            <td>
                <input type="text" name="item['. 1 .'][price]" class="price" value="15.99" />
            </td>
            <td>
                <input type="text" name="item['. 1 .'][per_pack]" class="per_pack" value="1000" />
            </td>
            <td>
                <input type="text" name="item['. 1 .'][quantity]" class="quantity" value="1" />
            </td>
            <td>
                <label class="subtotal"></label>
            </td>
        </tr>
    </tbody>
</table>
<p>
    <input type="button" id="buttonadd" value="Add Line" />
</p>

JQuery:

$(document).ready(function () {
    $counter = 1;
    $('#buttonadd').click(function () {
        $counter++;
        $('#invoiceitems > tbody:last').append('<tr><td><input type="button" class="buttondelete" value="Delete"/></td>\
        <td><input type="text" name="item[' + $counter + '][paper]" class="regular-text" value="" /></td>\
        <td><input type="text" name="item[' + $counter + '][price]" class="price" value="" /></td>\
        <td><input type="text" name="item[' + $counter + '][per_pack]" class="per_pack" value="" /></td>\
        <td><input type="text" name="item[' + $counter + '][quantity]" class="quantity" value="" /></td>\
        <td><label class="subtotal"></label> </td></tr>');
        $('.quantity , .price').unbind().on('change', function () {
            UpdateTotals(this);
        });
    });
});

$(document).ready(function () {
    $counter = 1;
    $('#buttondelete').click(function () {
        $counter++;
        $('#invoiceitems > tbody tr:last').remove();
        $('.quantity , .price').unbind().on('change', function () {
            UpdateTotals(this);
        });
    });
});

$(function () {
    CalculateSubTotals();
    CalculateTotal();
    // Adding the change events for the Price and
    // quantity fields only..
    // Changing the total should not affect anything
    $('.quantity , .price,').on('change', function () {
        UpdateTotals(this);
    });
});

function UpdateTotals(elem) {
    // This will give the tr of the Element Which was changed
    var $container = $(elem).parent().parent();
    var quantity = $container.find('.quantity').val();
    var price = $container.find('.price').val();
    var per_pack = $container.find('.per_pack').val();
    var subtotal = parseInt(quantity) * parseFloat(price) / parseInt(per_pack);
    $container.find('.subtotal').text(subtotal.toFixed(2));
    CalculateTotal();
}

function CalculateSubTotals() {
    // Calculate the Subtotals when page loads for the 
    // first time
    var lineTotals = $('.subtotal');
    var quantity = $('.quantity');
    var price = $('.price');
    var per_pack = $('.per_pack');
    $.each(lineTotals, function (i) {
        var tot = parseInt($(quantity[i]).val()) * parseFloat($(price[i]).val()) / parseInt($(per_pack[i]).val());
        $(lineTotals[i]).text(tot.toFixed(2));
    });
}

function CalculateTotal() {
    // This will Itearate thru the subtotals and
    // claculate the grandTotal and Quantity here
    var lineTotals = $('.subtotal');
    var quantityTotal = $('.quantity');
    var grandTotal = 0.0;
    var totalQuantity = 0;
    $.each(lineTotals, function (i) {
        grandTotal += parseFloat($(lineTotals[i]).text());
        totalQuantity += parseInt($(quantityTotal[i]).val())
    });

    $('.totalquantity').text(totalQuantity);
    $('.grandtotal').text(parseFloat(grandTotal).toFixed(2));

}
Community
  • 1
  • 1
rache_r
  • 29
  • 1
  • 10

2 Answers2

1

First remove the '[. 1 .'] from your HTML use [1] only like,

<input type="text" name="item[1][paper]" class="regular-text" 
      value="Glossy Paper A5" />

Combine all $(document).ready() into a single, also remove multiple unbind().on('change') use it once by using parent selector like table, use keyup inplace of change like,

$('table#invoiceitems').on('change', '.quantity , .price',function () {
     UpdateTotals(this);
});

And Delete Row should be like,

$('table#invoiceitems').on('click','.buttondelete',function () {
    $counter++;
    if($('table#invoiceitems tbody tr').length==1){
        alert('Cant delete single row');
        return false;
    }
    $(this).closest('tr').remove();
});

Full Code

$(document).ready(function () {
    $counter = 1;
    $('#buttonadd').click(function () {
        $counter++;
        $('#invoiceitems > tbody:last').append('<tr><td><input type="button" class="buttondelete" value="Delete"/></td>\
        <td><input type="text" name="item[' + $counter + '][paper]" class="regular-text" value="" /></td>\
        <td><input type="text" name="item[' + $counter + '][price]" class="price" value="" /></td>\
        <td><input type="text" name="item[' + $counter + '][per_pack]" class="per_pack" value="" /></td>\
        <td><input type="text" name="item[' + $counter + '][quantity]" class="quantity" value="" /></td>\
        <td><label class="subtotal"></label> </td></tr>');

    });
    $('table#invoiceitems').on('change', '.quantity , .price',function () {
        UpdateTotals(this);
    });

    $counter = 1;


    $('table#invoiceitems').on('click','.buttondelete',function () {
       $counter++;
       if($('table#invoiceitems tbody tr').length==1){
          alert('Cant delete single row');
          return false;
       }
       $(this).closest('tr').remove();
    });
    CalculateSubTotals();
    CalculateTotal();
});


function UpdateTotals(elem) {
    // This will give the tr of the Element Which was changed
    var $container = $(elem).parent().parent();
    var quantity = $container.find('.quantity').val();
    var price = $container.find('.price').val();
    var per_pack = $container.find('.per_pack').val();
    var subtotal = parseInt(quantity) * parseFloat(price) / parseInt(per_pack);
    $container.find('.subtotal').text(subtotal.toFixed(2));
    CalculateTotal();
}

function CalculateSubTotals() {
    // Calculate the Subtotals when page loads for the 
    // first time
    var lineTotals = $('.subtotal');
    var quantity = $('.quantity');
    var price = $('.price');
    var per_pack = $('.per_pack');
    $.each(lineTotals, function (i) {
        var tot = parseInt($(quantity[i]).val()) * parseFloat($(price[i]).val()) / parseInt($(per_pack[i]).val());
        $(lineTotals[i]).text(tot.toFixed(2));
    });
}

function CalculateTotal() {
    // This will Itearate thru the subtotals and
    // claculate the grandTotal and Quantity here
    var lineTotals = $('.subtotal');
    var quantityTotal = $('.quantity');
    var grandTotal = 0.0;
    var totalQuantity = 0;
    $.each(lineTotals, function (i) {
        grandTotal += parseFloat($(lineTotals[i]).text());
        totalQuantity += parseInt($(quantityTotal[i]).val())
    });
    $('.totalquantity').text(totalQuantity);
    $('.grandtotal').text(parseFloat(grandTotal).toFixed(2));
}

Working Demo

Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
  • quess there is still a problem with the calc. on beginning the price is way to low... it should be 15,99 and not 0,15 :) – Dwza Jan 07 '14 at 10:18
  • Thank you, your solution solved the issues i have been having. would you also explain to me please why the $(document).ready() should all be combined? Or is it simply because it simplifies the code and is more efficient? @Rohan Kumar – rache_r Jan 07 '14 at 10:23
  • Yes it simplifies the code and also it may improve the `performance` Read http://stackoverflow.com/questions/1148241/jquery-is-it-bad-to-have-multiple-document-readyfunction – Rohan Kumar Jan 07 '14 at 10:27
  • i was wondering if there was a way to incorporate an autocomplete searchbox that will allow the user to search for an item and its description, price and per pack value is displayed in another box? @Rohan Kumar – rache_r Jan 07 '14 at 10:49
0

Your Main Problem: Multi-line strings in JavaScript MUST end with a backslash on every line.

This is what's causing NOTHING to work!

Console error:

Uncaught SyntaxError: Unexpected token <


Example of bad string:

var string = "abc
              def
              ghi";

Correct example:

var string = "abc\
              def\
              ghi";
Samuel Liew
  • 76,741
  • 107
  • 159
  • 260
  • i am pretty new this JavaScript, would you kindly explain why multi-line strings must end with a backslash? or is it just a mandatory syntax thing? @Samuel Liew – rache_r Jan 07 '14 at 10:15