1

I have multiple input arrays (see snippet). I need to calculate all of the entered values to a variables. It is an invoice creation, so I want to know the total price of all items with discount. How can I achieve this?

This is what I have for now:

$('#addNewPosition').on('click', function(e) {
            e.preventDefault();
            $('#positions').append('<input type="text" name="item[]" placeholder="Item" class="form-control">\n' +
                '            <input type="number" step="any" name="price[]" placeholder="Price" class="form-control">\n' +
                '            <input type="number" name="item_discount[]" placeholder="Discount, %" class="form-control">\n' +
                '            <input type="number" step="any" name="quantity[]" placeholder="Quantity" class="form-control">\n' +
                '            <input type="text" name="quantity_index[]" placeholder="Unit" class="form-control">\n' +
                '            <input type="text" name="description[]" placeholder="Description" class="form-control">\n');
        });

// Get the number of all items added:
var count = $("input[name='item[]']").map(function() {
  return $(this).val();
}).get().length;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="positions">
  <input type="number" step="any" name="price[]" placeholder="Price" class="form-control">
  <input type="number" name="item_discount[]" placeholder="Discount, %" class="form-control">
  <input type="number" step="any" name="quantity[]" placeholder="Quantity" class="form-control">
  <input type="text" name="quantity_index[]" placeholder="Unit" class="form-control">
  <input type="text" name="description[]" placeholder="Description" class="form-control">
  <a href="#" id="addNewPosition" class="btn btn-green">Add new</a>
</div>

All I want to achieve is to calculate the total price: total = ((each field's price) - discount, %) * quantity

Is there any way I can do that? Kind regards

5
  • when you want it to show? after a button click or auto updating when user interact with the inputs? Commented Aug 27, 2020 at 21:26
  • Where do you want to see the result? In console? In some element? Commented Aug 27, 2020 at 21:26
  • 1
    Why are you using .length That is giving you the array length you just created. You should use reduce() after the map Commented Aug 27, 2020 at 21:28
  • 1
    Does this help? stackoverflow.com/questions/19010177/… Commented Aug 27, 2020 at 21:34
  • This is in my modal and then I want to pass it to the parent, @Anton. And I am using length to determine the length of the array, cause I thought I could use for loop Commented Aug 27, 2020 at 21:36

2 Answers 2

2

You can delegate the input event in order to compute the total each time a price or a discount changes.

In order to achive your result you can combine .map() with .reduce()

$('#addNewPosition').on('click', function (e) {
    e.preventDefault();
    $('#positions').append('<div class="form-group">' +
            '<div class="col-sm-1"></div><div class="col-sm-3"><input type="text" name="item[]" placeholder="Item" class="form-control"></div>\n' +
            '            <div class="col-sm-1"><input type="number" step="any" name="price[]" placeholder="Price" class="form-control"></div>\n' +
            '            <div class="col-sm-1"><input type="number" name="item_discount[]" placeholder="Discount, %" class="form-control"></div>\n' +
            '            <div class="col-sm-1"><input type="number" step="any" name="quantity[]" placeholder="Quantity" class="form-control"></div>\n' +
            '            <div class="col-sm-1"><input type="text" name="quantity_index[]" placeholder="Unit" class="form-control"></div>\n' +
            '            <div class="col-sm-3"><input type="text" name="description[]" placeholder="Description" class="form-control"></div>\n' +
            '</div>');
});

$(document).on('input', 'input[name="price[]"], input[name="item_discount[]"], input[name="quantity[]"]', function (e) {
    var price = $('input[name="price[]"]').map(function (idx, ele) {
        return $(ele).val().trim().length == 0 ? 0 : parseFloat($(ele).val().trim());
    }).get();
    var discount = $('input[name="item_discount[]"]').map(function (idx, ele) {
        return $(ele).val().trim().length == 0 ? 0 : parseFloat($(ele).val().trim());
    }).get();
    var quantity = $('input[name="quantity[]"]').map(function (idx, ele) {
        return $(ele).val().trim().length == 0 ? 0 : parseFloat($(ele).val().trim());
    }).get();
    var total = price.reduce(function (a, v, i) {
        return a + (v - (v * discount[i] / 100)) * quantity[i];
    }, 0);
    console.log('total=' + total);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<div id="positions">
    <div class="col-sm-1">
        <input type="number" step="any" name="price[]" placeholder="Price" class="form-control">
    </div>

    <div class="col-sm-1">
        <input type="number" name="item_discount[]" placeholder="Discount, %" class="form-control">
    </div>

    <div class="col-sm-1">
        <input type="number" step="any" name="quantity[]" placeholder="Quantity" class="form-control">
    </div>

    <div class="col-sm-1">
        <input type="text" name="quantity_index[]" placeholder="Unit" class="form-control">
    </div>

    <div class="col-sm-3">
        <input type="text" name="description[]" placeholder="Description" class="form-control">
    </div>

    <a href="#" id="addNewPosition" class="btn btn-green">Add new</a>
</div>

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the reply! There is no quantity, and I tried to add a var quantity = $('input[name="quantity[]"]').map(function(idx, ele) { return $(ele).val().trim().length == 0 ? 0 : parseFloat($(ele).val().trim()); }).get(); and in the return return (a - (v * discount[i] / 100)) * quantity;, but the total is NaN
I've entered 123 (price), 10 (discount), 3 (amount) into your code snippet and it shows me total=1230. Seems strange
1

Here's another workaround. But this is in VanillaJS, you can just turn it into Jquery.

(function(){

  let addNewButton = document.getElementById("addLineButton");

  let baseItem = document.getElementById("_base");
  let container = document.getElementById('content');

  function createItem(idNumber){
    let newItemNode = baseItem.cloneNode(true);
    newItemNode.id = "_" + idNumber;
    container.insertBefore(newItemNode, document.getElementById("totals"));

    document.querySelectorAll(".editable").forEach((input)=>{
      input.addEventListener("keyup", (event)=>{
        performCalculation(input);
      });
    })
  }

  addNewButton.addEventListener('click', (event)=>
  {
    let currentItemCount = document.getElementsByClassName("item-container").length;
    createItem(currentItemCount);
  });

  function performCalculation(input)
  {
    var cId = input.closest("tr.item-container").id; // container id <tr>
    var qtyVal = document.querySelector(`#${cId} .quantity input`).value;
    var priceVal = document.querySelector(`#${cId} .price input`).value;
    var discountVal = document.querySelector(`#${cId} .discount input`).value;
    var lineTotalElement = document.querySelector(`#${cId} .total input`);
    if(qtyVal && discountVal && priceVal)
    {
      lineTotalElement.value= Number((priceVal * (1 - (discountVal/100))) * qtyVal).toFixed(2);
      performTotal();
    }
  }

  function performTotal()
  {
    let element = document.getElementById("totalPrice");
    let totalPrice = Number(0);
    document.querySelectorAll(".item.total input").forEach((linePrice)=>{
      totalPrice += Number(linePrice.value);
    });
    element.value = totalPrice.toFixed(2);
  }
})();
tr input{
  border: none;
  border-bottom: 2px solid gray;
  padding: 0.25rem;
}
tr td:last-child input{
  background-color: whitesmoke;
}


tr#totals{
  border-top: thin solid gray;
  padding: 0.25rem 0; 

}
#_base{
  display: none;
}
<!DOCTYPE html>
<html>

<head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" />
    <link href="./src/styles.css" rel="stylesheet" />

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
</head>

<body>
    <table class="table table-light">
        <thead>
            <tr>
                <th scope="col" class="item description">Description</th>
                <th scope="col" class="item quantity">Quantity</th>
                <th scope="col" class="item price">Price</th>
                <th scope="col" class="item discount">Discount</th>
                <th scope="col" class="item total">Line Total</th>
            </tr>
        </thead>
        <tbody id="content">
            <tr id="_base" class="item-container">
                <th scope="col" class="item description">
                    <input class="editable" placeholder="Description" />
                </th>
                <th scope="col" class="item quantity">
                    <input class="editable" placeholder="Quantity" />
                </th>
                <th scope="col" class="item price">
                    <input class="editable" placeholder="Unit Price" />
                </th>
                <th scope="col" class="item discount">
                    <input class="editable" placeholder="Discount" />
                </th>
                <th scope="col" class="item total">
                    <input disabled />
                </th>
            </tr>
            <tr id="totals" class="item-container">
                <th scope="col" >
                </th>
                <th scope="col" >
                </th>
                <th scope="col" >
                </th>
                <th scope="col" >
                    Line Total
                </th>
                <th scope="col" class="item overallTotal">
                    <input id="totalPrice" disabled />
                </th>
            </tr>
        </tbody>
    </table>
    <button id="addLineButton">Add Line</button>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="src/index.js">
    </script>
</body>

</html>

Find Codesandbox here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.