最新消息: 雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Calculate on change for each row - Stack Overflow

programmer admin 22浏览 0评论

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.

发布评论

评论列表(0)

  1. 暂无评论