Jump to content

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.

Please, the experts in the house who always rescue us from our downfall should please help me address this query.

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

                <button type="button" id="add-order-btn" class="w3-button w3-blue w3-block"><i class="far fa-plus-square"> </i> Add Order</button>
            </div>

            <!-- Fee List Section -->
            <div class="w3-half w3-padding w3-form-container">
    <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-container w3-padding">
                <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>
    <thead>
        <tr class="bg-gradient bg-dark-subtle">
            <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>
    </thead>
    <tbody>
        <tr class="noData">
            <th class="w3-center w3-border" colspan="3">No Item Listed Yet</th>
        </tr>
    </tbody>

    <tfoot>
         <tr class="bg-gradient bg-dark-subtle bg-opacity-50">
            <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>
        <tr class="bg-gradient bg-dark-subtle bg-opacity-50">
            <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>
        <tr class="bg-gradient bg-dark-subtle bg-opacity-50">
            <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>
        <tr class="bg-gradient bg-dark-subtle bg-opacity-50">
            <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>
  
$(document).ready(function () {
    const orderItemTbl = $('#order-item-tbl');
    const addOrderBtn = $('#add-order-btn');
    const lessTotalText = $('#lessTotal');
    const subTotalText = $('#subTotalText');

    let totalLessAmount = 0;
    let totalPriceForFeeDescriptions = 0;

    addOrderBtn.click(function (e) {
        e.preventDefault();
        addItem();
    });

    function addItem() {
        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
        updateSubTotal();
        // 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);
                }
                updateSubTotal();
                updateTotalLessAmount();
            }
        });

        return tr;
    }

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

    function updateSubTotal() {
        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, ','));
    }
});

 

sample pic.png

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');

    addOrderBtn.click(function (e) {
        e.preventDefault();
        addItem();
    });

It needs to be

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

    $(addOrderBtn).click(function (e) {                                  // note the $(addOrderBtn)
        e.preventDefault();
        addItem();
    });

Use your browser's developer tools to debug your JS code

  • Great Answer 1
  • 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.

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 addOrderBtn = $('#add-order-btn');
    const lessTotalText = $('#lessTotal');
    const subTotalText = $('#subTotalText');

    let totalLessAmount = 0;
    let totalPriceForFeeDescriptions = 0;

    $(addOrderBtn).click(function (e) {
        e.preventDefault();
        addItem();
    });

    function addItem() {
        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);
            console.log("totalLessAmount after adding:", totalLessAmount);
        } else {
            orderItemTbl.find('tbody').append(tr);

            // Update total price for fee descriptions
            totalPriceForFeeDescriptions += parseFloat(price);
            console.log("totalPriceForFeeDescriptions after adding:", totalPriceForFeeDescriptions);
        }

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

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

        // Update subtotal
        updateSubTotal();
        // 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);
                }
                updateSubTotal();
                updateTotalLessAmount();
            }
        });

        return tr;
    }

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

    function updateSubTotal() {
        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

console.png

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

image.thumb.png.3a87589219387004710ed2a85a890f8a.png

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

image.png.9a76e831455b6424fe3de5ce41d9dfb2.png

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

  • Like 1
6 minutes ago, Barand said:

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

image.thumb.png.3a87589219387004710ed2a85a890f8a.png

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

image.png.9a76e831455b6424fe3de5ce41d9dfb2.png

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.