# JavaScript Calculation Challenge: Updating Sub-Total and Total Less Amount Dynamically in a Table

Go to solution Solved by Barand,

## Recommended Posts

Hi,

I am working on this script for invoice generation, from the image attached, is the input forms at left hand side, when the add order button is clicked, it add the fee description, amount, less fee description and amount less to the fee list as shown in the right hand side of the image.

In the table in the right hand, Total less item(s) will sum all the amount less), sub-total will sum all the amount and subtract it from the total less. I still have to do discount and grandtotal but I had challenges with the sub-total, giving me the same value with the Total Less Amount.

Here is the html form

```<div class="w3-half w3-padding">
<label for="item">Fee Description:</label>
<input type="text" id="item" class="w3-input w3-border" autocomplete="off">
</div>
<label for="price">Amount:</label>
<input type="number" id="price" class="w3-input w3-border" autocomplete="off">
</div>
<label for="less">Less Fee Description:</label>
<input type="text" id="less" class="w3-input w3-border" autocomplete="off">
</div>
<label for="less_amount">Amount Less:</label>
<input type="number" id="less_amount" class="w3-input w3-border" autocomplete="off">
</div>
</div></div>

</div>

<!-- Fee List Section -->
<h2 class="w3-margin-bottom">Fee List</h2>
<div id="fee-list-content">
<!-- testing -->
<div class="w3-card w3-round w3-margin card-body">
<div class="w3-responsive">

<table class="w3-table w3-hoverable w3-bordered w3-striped" id="order-item-tbl">
<colgroup>
<col width="5%">
<col width="70%">
<col width="20%">
</colgroup>
<th class="bg-transparent w3-center w3-border"></th>
<th class="bg-transparent w3-center w3-border">Fee Description</th>
<th class="bg-transparent w3-center w3-border">Price</th>
</tr>
<tbody>
<tr class="noData">
<th class="w3-center w3-border" colspan="3">No Item Listed Yet</th>
</tr>
</tbody>

<tfoot>
<th class="bg-transparent w3-center w3-border" colspan="2">Total Less Item(s)</th>
<th class="bg-transparent w3-border w3-right-align" id="lessTotal">0</th>
</tr>
<th class="bg-transparent w3-center w3-border" colspan="2">Sub-Total</th>
<th class="bg-transparent w3-border w3-right-align" id="subTotalText">0</th>
</tr>
<th class="bg-transparent w3-center w3-border" colspan="2">Discount Amount</th>
<th class="bg-transparent w3-border">
<input type="number" class="w3-input w3-small w3-round w3-right-align" step="any" name="discount_amount" id="discount_amount" min="0" max="1000000" value="0">
</th>
</tr>
<th class="bg-transparent w3-center w3-border" colspan="2">Grand Total</th>
<th class="bg-transparent w3-border w3-right-align" id="grandTotalText">0</th>
</tr>
</tfoot>
</table>```

Here is my javascript

```//<script>

const orderItemTbl = \$('#order-item-tbl');
const lessTotalText = \$('#lessTotal');
const subTotalText = \$('#subTotalText');

let totalLessAmount = 0;
let totalPriceForFeeDescriptions = 0;

e.preventDefault();
});

var item = \$('#item').val();
var price = \$('#price').val();
var less = \$('#less').val();
var lessAmount = \$('#less_amount').val();

// Validate input fields
if (item === '' || price === '' || price < 1) {
return false;
}

price = parseFloat(price).toFixed(2); // two decimal places
var tr = createRow(item, price);

// Check if less and lessAmount are provided
if (less !== '' && lessAmount !== '') {
var tr2 = createRow(less, lessAmount);

orderItemTbl.find('tbody').append(tr, tr2);

// Update total less amount
totalLessAmount += parseFloat(lessAmount);
} else {
orderItemTbl.find('tbody').append(tr);

// Update total price for fee descriptions
totalPriceForFeeDescriptions += parseFloat(price);
}

orderItemTbl.find('tbody tr.noData').hide();

// Clear input fields after adding an item
clearInputFields();

// Update subtotal
// Update total less amount
updateTotalLessAmount();
}

function createRow(description, amount) {
var tr = \$('<tr>');
var removeBtn = \$('<button type="button" class="remove-item w3-button w3-red w3-round w3-tiny"><i class="fas fa-times"></i></button>');
tr.append('<td class="w3-center w3-border"></td>');
tr.append(`<td class="w3-border">\${description}</td>`);
tr.append(`<td class="w3-right-align w3-border numeric">\${parseFloat(amount).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</td>`);

tr.find('td:first-child').append(removeBtn);

removeBtn.click(function () {
if (confirm('Are you sure to remove this item?')) {
tr.remove();
clearInputFields();
if (orderItemTbl.find('tbody tr').length <= 1) {
orderItemTbl.find('tbody tr.noData').show();
}
if (amount !== '' && parseFloat(amount) > 0) {
totalLessAmount -= parseFloat(amount);
}
updateTotalLessAmount();
}
});

return tr;
}

function clearInputFields() {
\$('#item').val('');
\$('#price').val('');
\$('#less').val('');
\$('#less_amount').val('');
}

var subTotal = totalPriceForFeeDescriptions - totalLessAmount;
subTotalText.text(subTotal.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ','));
}

function updateTotalLessAmount() {
lessTotalText.text(totalLessAmount.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ','));
}
});```

##### Share on other sites

Your HTML markup contains many mis-matched <Div..</DIV> tags.

Your JQuery is wrong. For example, this doesn't work - addItem() is not called.

```const addOrderBtn = \$('#add-order-btn');

e.preventDefault();
});```

It needs to be

```const addOrderBtn = \$('#add-order-btn');

e.preventDefault();
});```

##### Share on other sites

It is not showing error in my browser console both on chrome and edge.

I don't know why?

##### Share on other sites

• Solution

Use the javascript debugger to step through the code to see if it's doing what you expect and that the variables contain what you expect.

##### Share on other sites

13 hours ago, Barand said:

Use the javascript debugger to step through the code to see if it's doing what you expect and that the variables contain what you expect.

After using the debugger by add console log, I still don't noticed where the issue is. And you also please tell me the anomalies in my html div tags?

```\$(document).ready(function () {
const orderItemTbl = \$('#order-item-tbl');
const lessTotalText = \$('#lessTotal');
const subTotalText = \$('#subTotalText');

let totalLessAmount = 0;
let totalPriceForFeeDescriptions = 0;

e.preventDefault();
});

var item = \$('#item').val();
var price = \$('#price').val();
var less = \$('#less').val();
var lessAmount = \$('#less_amount').val();

// Validate input fields
if (item === '' || price === '' || price < 1) {
return false;
}

price = parseFloat(price).toFixed(2); // two decimal places
var tr = createRow(item, price);

// Check if less and lessAmount are provided
if (less !== '' && lessAmount !== '') {
var tr2 = createRow(less, lessAmount);

orderItemTbl.find('tbody').append(tr, tr2);

// Update total less amount
totalLessAmount += parseFloat(lessAmount);
} else {
orderItemTbl.find('tbody').append(tr);

// Update total price for fee descriptions
totalPriceForFeeDescriptions += parseFloat(price);
}

orderItemTbl.find('tbody tr.noData').hide();

// Clear input fields after adding an item
clearInputFields();

// Update subtotal
// Update total less amount
updateTotalLessAmount();
}

function createRow(description, amount) {
var tr = \$('<tr>');
var removeBtn = \$('<button type="button" class="remove-item w3-button w3-red w3-round w3-tiny"><i class="fas fa-times"></i></button>');
tr.append('<td class="w3-center w3-border"></td>');
tr.append(`<td class="w3-border">\${description}</td>`);
tr.append(`<td class="w3-right-align w3-border numeric">\${parseFloat(amount).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</td>`);

tr.find('td:first-child').append(removeBtn);

removeBtn.click(function () {
if (confirm('Are you sure to remove this item?')) {
tr.remove();
clearInputFields();
if (orderItemTbl.find('tbody tr').length <= 1) {
orderItemTbl.find('tbody tr.noData').show();
}
if (amount !== '' && parseFloat(amount) > 0) {
totalLessAmount -= parseFloat(amount);
console.log("totalLessAmount after removing:", totalLessAmount);
}
updateTotalLessAmount();
}
});

return tr;
}

function clearInputFields() {
\$('#item').val('');
\$('#price').val('');
\$('#less').val('');
\$('#less_amount').val('');
}

var subTotal = totalPriceForFeeDescriptions - totalLessAmount;
console.log("totalPriceForFeeDescriptions:", totalPriceForFeeDescriptions);
console.log("totalLessAmount:", totalLessAmount);
subTotalText.text(subTotal.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ','));
}

function updateTotalLessAmount() {
lessTotalText.text(totalLessAmount.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ','));
}
});```

Attached picture

##### Share on other sites

Thank you @Barand I modified my html form and my Javascript to triggered the calculations in real time as I type. Now, it is time for me to bind my parameters.

##### Share on other sites

The highlighted </div> tags have no corresponding <div> tags...

When the page is run, the browser adds five </div> tags at the end to close off unclosed div elements...

In addition, your table markup is inconsistent, with some rows having three columns and others only having two.

##### Share on other sites

6 minutes ago, Barand said:

The highlighted </div> tags have no corresponding <div> tags...

When the page is run, the browser adds five </div> tags at the end to close off unclosed div elements...

In addition, your table markup is inconsistent, with some rows having three columns and others only having two.

I have corrected it. Thanks so much.

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

×   Pasted as rich text.   Restore formatting

Only 75 emoji are allowed.