admin管理员组

文章数量:1335183

I have an invoice form to generate a PDF. I want to calculate the inputs after the change of the value that the user fills in the form.

I can calculate the first row, but i want to (1) calculate each row and at the end to (2) calculate all the colums properly. For the first step just to the (1) and i will make the total calculation.

The problem is that i generate the rows with dynamic name and id because i post them in an array to the database. For this example the id is the same for every row of inputs.

PS: i cannot make .change work and i use $(document).on('change', '#qty', function (e) { calculateLine(); }); to trigger the calculation function for each input. I dont know why .change is not working as it support to, with latest jquery.

[invoice.php]

<script>
    $(document).ready(function () {

        $(document).on('change', '#qty', function (e) { calculateLine(); });
        $(document).on('change', '#price', function (e) { calculateLine(); });
        $(document).on('change', '#discount', function (e) { calculateLine(); });
        $(document).on('change', '#discountPrice', function (e) { calculateLine(); });

    });
</script>

[invoice.js]

function calculateLine() {

    var qty = parseFloat($('#qty').val());
    var price = parseFloat($('#price').val());
    var discount = parseFloat($('#discount').val());
    var discountPrice = parseFloat($('#discountPrice').val());
    var vat = parseFloat($('#vat').val());

    var netTotal = 0;
    var total = 0;
    var vatAmount = 0;

    if (!qty && qty == 0) {
        return;
    }
    if (!price && price == 0) {
        return;
    }

    netTotal = qty * price;

    if ((!discount || discount == 0) && discountPrice != 0) {
        discount = (discountPrice / netTotal) * 100;
    }
    if ((!discountPrice || discountPrice == 0) && discount != 0) {
        discountPrice = (netTotal / 100) * discount;
    }
    if (discountPrice != 0 && discount != 0) {
        discountPrice = (netTotal / 100) * discount;
    }
    if ((!discount || discount == 0) && (!discountPrice || discountPrice == 0)) {
        discountPrice = 0;
        discount = 0;
    }

    total = netTotal - discountPrice;

    if (!total || total == 0) {
        total = 0;
    }
    vatAmount = (total / 100) * vat;

    $('#total').val(total);
    $('#discount').val(discount);
    $('#discountPrice').val(discountPrice);
    $('#vatAmount').val(vatAmount);

    //calculateTotal();
}

[html]

<tr>
    <td class="col-xs-0">
        <input type="checkbox" name="selected[]" class="checkall">
    </td>
    <td class="col-xs-5">
        <textarea type="text" name="invoice[item][{{j}}][description]" class="form-control description" rows="1" ></textarea>
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][unit]" class="form-control unit" value="" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][qty]" class="form-control qty" value="" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][price]" class="form-control price" value="" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][discount]" class="form-control discount" value="" >
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][discountPrice]" class="form-control discountPrice" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][total]" class="form-control total" value="" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][vat]" class="form-control vat" value="{{invcl_vat}}" readonly />
        <input type="hidden" name="invoice[item][{{j}}][vatAmount]" class="form-control vatAmount" value="" readonly />
    </td>
</tr>

I have an invoice form to generate a PDF. I want to calculate the inputs after the change of the value that the user fills in the form.

I can calculate the first row, but i want to (1) calculate each row and at the end to (2) calculate all the colums properly. For the first step just to the (1) and i will make the total calculation.

The problem is that i generate the rows with dynamic name and id because i post them in an array to the database. For this example the id is the same for every row of inputs.

PS: i cannot make .change work and i use $(document).on('change', '#qty', function (e) { calculateLine(); }); to trigger the calculation function for each input. I dont know why .change is not working as it support to, with latest jquery.

[invoice.php]

<script>
    $(document).ready(function () {

        $(document).on('change', '#qty', function (e) { calculateLine(); });
        $(document).on('change', '#price', function (e) { calculateLine(); });
        $(document).on('change', '#discount', function (e) { calculateLine(); });
        $(document).on('change', '#discountPrice', function (e) { calculateLine(); });

    });
</script>

[invoice.js]

function calculateLine() {

    var qty = parseFloat($('#qty').val());
    var price = parseFloat($('#price').val());
    var discount = parseFloat($('#discount').val());
    var discountPrice = parseFloat($('#discountPrice').val());
    var vat = parseFloat($('#vat').val());

    var netTotal = 0;
    var total = 0;
    var vatAmount = 0;

    if (!qty && qty == 0) {
        return;
    }
    if (!price && price == 0) {
        return;
    }

    netTotal = qty * price;

    if ((!discount || discount == 0) && discountPrice != 0) {
        discount = (discountPrice / netTotal) * 100;
    }
    if ((!discountPrice || discountPrice == 0) && discount != 0) {
        discountPrice = (netTotal / 100) * discount;
    }
    if (discountPrice != 0 && discount != 0) {
        discountPrice = (netTotal / 100) * discount;
    }
    if ((!discount || discount == 0) && (!discountPrice || discountPrice == 0)) {
        discountPrice = 0;
        discount = 0;
    }

    total = netTotal - discountPrice;

    if (!total || total == 0) {
        total = 0;
    }
    vatAmount = (total / 100) * vat;

    $('#total').val(total);
    $('#discount').val(discount);
    $('#discountPrice').val(discountPrice);
    $('#vatAmount').val(vatAmount);

    //calculateTotal();
}

[html]

<tr>
    <td class="col-xs-0">
        <input type="checkbox" name="selected[]" class="checkall">
    </td>
    <td class="col-xs-5">
        <textarea type="text" name="invoice[item][{{j}}][description]" class="form-control description" rows="1" ></textarea>
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][unit]" class="form-control unit" value="" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][qty]" class="form-control qty" value="" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][price]" class="form-control price" value="" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][discount]" class="form-control discount" value="" >
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][discountPrice]" class="form-control discountPrice" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][total]" class="form-control total" value="" />
    </td>
    <td class="col-xs-1">
        <input type="text" name="invoice[item][{{j}}][vat]" class="form-control vat" value="{{invcl_vat}}" readonly />
        <input type="hidden" name="invoice[item][{{j}}][vatAmount]" class="form-control vatAmount" value="" readonly />
    </td>
</tr>
Share Improve this question edited Jul 9, 2014 at 7:48 John Priestakos asked Jul 9, 2014 at 7:07 John PriestakosJohn Priestakos 3905 silver badges19 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 6

You haven't shown your HTML, but it's clear from your question that you're using the same id (qty, etc.) on more than one element. You can't do that. Every id must be unique on the page. In this case, you'd probably use classes instead.

The general way that you do what you're talking about is indeed to use delegated event handling, then find the containing row, and use that as the starting point looking for descendant inputs using classes rather than ids:

$("selector-for-the-table").on("change", "input", function() {
    // Get the row containing the input
    var row = $(this).closest("tr");

    // Get the values from _this row's_ inputs, using `row.find` to
    // look only within this row
    var qty = parseFloat(row.find('.qty').val());
    var price = parseFloat(row.find('.price').val());
    var discount = parseFloat(row.find('.discount').val());
    var discountPrice = parseFloat(row.find('.discountPrice').val());
    var vat = parseFloat(row.find('.vat').val());

    // ...
});

I've also rooted that on the table, rather than document, so it only applies where appropriate.

Live (Simplified) Example:

<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery./jquery-1.11.0.min.js"></script>
  <meta charset="utf-8">
  <title>Example</title>
</head>
<body>
  <table>
    <thead>
      <tr>
        <th>Quantity</th>
        <th>Price</th>
        <th>Total</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><input type="text" class="qty"></td>
        <td><input type="text" class="price"></td>
        <td><input type="text" class="total" disabled></td>
      </tr>
      <!-- ...and so on... -->
    </tbody>
  </table>
<script>
  (function() {
    "use strict";

    $("table").on("change", "input", function() {
      var row = $(this).closest("tr");
      var qty = parseFloat(row.find(".qty").val());
      var price = parseFloat(row.find(".price").val());
      var total = qty * price;
      row.find(".total").val(isNaN(total) ? "" : total);
    });
  })();
</script>
</body>
</html>

You've said before that the names are dynamic. Surely there is some characteristic of the fields you're trying to find that is consistent, or you can make them consistent. In the worst case (and I mean in the worst case), you could do something based on position — the first input in the row is row.find("input:eq(0)"), the second is row.find("input:eq(1)"), and so on.

Live Example Using eq:

<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery./jquery-1.11.0.min.js"></script>
  <meta charset="utf-8">
  <title>Example</title>
</head>
<body>
  <table>
    <thead>
      <tr>
        <th>Quantity</th>
        <th>Price</th>
        <th>Total</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><input type="text"></td>
        <td><input type="text"></td>
        <td><input type="text" disabled></td>
      </tr>
      <!-- ...and so on... -->
    </tbody>
  </table>
<script>
  (function() {
    "use strict";

    $("table").on("change", "input", function() {
      var row = $(this).closest("tr");
      var qty = parseFloat(row.find("input:eq(0)").val());
      var price = parseFloat(row.find("input:eq(1)").val());
      var total = qty * price;
      row.find("input:eq(2)").val(isNaN(total) ? "" : total);
    });
  })();
</script>
</body>
</html>

But avoid that if you possibly can, it's fragile — if you change the order of columns, you have to change your code.

本文标签: javascriptCalculate on change for each rowStack Overflow