0

I have two columns, Quantity and Pricing. Another column Total which is computed using jQuery functions.

Here's the code for how I'm calculating the Total column:

$('#TableBodyId').on("keyup keypress blur change", "input.proposal-line-pricing, input.proposal-line-quantity", function () {
    var result = 1,
        $this = $(this).parents('tr');
    $this.find('input.proposal-line-pricing, input.proposal-line-quantity').each(function () {
        result *= parseFloat(this.value);
    });
    $this.find("input.proposal-line-total").val(parseFloat(result).toFixed(2));
});

At the footer of the table, is a div which displays the sum of the Total column.

Here's the code for how I'm calculating the sum:

$('#TableBodyId').on("keyup keypress blur change", "input.proposal-line-total", function () {
    var $pricings = $("#TableBodyId").find(".proposal-line-total");
    var pricingTotal = self.calculateSum($pricings);
    $("#PricingTotal strong").html(parseFloat(pricingTotal).toFixed(2));
});

To reflect the change in the footer, I had to trigger something in the total column or it won't change. Right now, I'm doing it like this:

window.setInterval(function () {
    $('input.proposal-line-total').trigger("blur")
}, 500);  

Is there any other way to not poll the page every 500ms and implement it efficiently? I need it to immediately reflect the change in the div.

Awais Syed
  • 51
  • 9

2 Answers2

1

I'm assuming you want to update your row Total and grand Total after every single change you make in your Quantity and Price inputs.

To do so:

  1. listen for keyboard events and change events in your Quantity and Price inputs and do as follows:
  2. calculate one row's total and display it
  3. accumulate all row totals into a grand total and display it

Here's a solution: https://codepen.io/anon/pen/BdvXMb

// binding event listener for every keyup
// IMPORTANT: don't forget to deal with non numerical values when parsing
$("#basket input").on("keyup change", function () {
    var thisRow = $(this).parent();
    // retrieving the price value
    var price = parseFloat(thisRow.children(".price").val());
    // retrieving the quantity value
    var quantity = parseFloat(thisRow.children(".quantity").val());
    // if there are invalid inputs at any moment, stop the function
    if (isNaN(price) || isNaN(quantity)) {
        return false;
    }
    // calculating the total value of this row
    var rowTotal = (price * quantity).toFixed(2);
    // displaying the total value of this row
    thisRow.children(".total").text(rowTotal);
    var grandTotal = 0;
    var allRows = thisRow.parent().find(".item");
    // get the total colum of each row and accumulate their values
    allRows.find(".total").each(function () {
        var rowTotal = parseFloat($(this).text());
        grandTotal += rowTotal;
    });
    // display the grand total value
    $("#grand-total").html(grandTotal.toFixed(2));
});
/* HTML:
<div id="basket">
  <div class="item">
    <input class="price">
    <input class="quantity">
    <div class="total">0</div>
  </div>
  <div class="item">
    <input class="price">
    <input class="quantity">
    <div class="total">0</div>
  </div>
</div>
<div>Grand total: <span id="grand-total">0</span></div>
*/
/* CSS:
.item {
   display: flex;
}
*/

EDIT: If you want to dynamically add new rows to the table, you can separate the anonymous function and assign it a variable then attach it to every new row inputs you append to the table later on. https://codepen.io/anon/pen/xLMxXo

var handleInputChange = function () { /* same as above */ }
var basket = $("#basket");
var newItemRow = $("..."); // your row html here
newItemRow.find("input").on("keyup change", handleInputChange);
newItemRow.appendTo(basket);
nvbach91
  • 166
  • 8
0

Instead of refreshing every 500ms, try refreshing when there is a change in your div, and you can add a timer so the event does not trigger twice and wait until the previous action is finished (please add the html if possible).

  • Please see https://stackoverflow.com/questions/17029211/how-to-add-a-wait-timer-on-an-input-field-keyup-event – Mauricio Cárdenas Aug 31 '17 at 21:17
  • I'm using handlebars and backbone.js to generate the new rows when clicked on a button. The code would be too big to post. Should I do it still? – Awais Syed Aug 31 '17 at 21:19
  • I'd like to see at least the div and one row if possible. If not, you can try with post above answer. You just need to change the trigger so it fires right after the previous actions are finished instead of being triggered by user input. Another option is to set the trigger as a callback so it fires automatically after previous actions are finished. – Mauricio Cárdenas Aug 31 '17 at 21:31