views:

65

answers:

1

Greetings,

I am trying to code a solution for an order form pricing calculator using the excellent calculation plugin. My form has two different prices for each item, one for quantities under 10 and one for quantities over that amount.

This is the code I have so far:

$(document).ready(function() {

    // bind the recalc function to the quantity fields
    $("input[name^=qty_item_]").bind("keyup", recalc);
    // run the calculation function now
    recalc();

    function recalc() {

        var quantity = $("input[name^=qty_item_]").val();
        var quantity_int = parseInt(quantity_str);
        var threshold = 10;
        if (quantity_int < threshold) {
            var useprice = $("[id^=price_item_1_]");
        } else {
            var useprice = $("[id^=price_item_2_]");
        }

        $("[id^=total_item_]").calc(

            // the equation to use for the calculation
            "qty * price",
            // define the variables used in the equation, these can be a jQuery object
            {
                qty: $("input[name^=qty_item_]"),
                price: useprice
            },
            // define the formatting callback, the results of the calculation are passed to this function
            function (s){
                // return the number as a dollar amount
                return "$" + s.toFixed(2);
            },
            // define the finish callback, this runs after the calculation has been complete
            function ($this){
                // sum the total of the $("[id^=total_item]") selector
                var sum = $this.sum();
                $("#grand_total").text(
                    // round the results to 2 digits
                    "$" + sum.toFixed(2)
                );
            }

        );

    }

});

It's close, but useprice stays at the value it is set for for the first item in the field array. I'm thinking I need to bring the useprice calculation 'inside the loop' somehow, but I'm stuck as to how.

UPDATE: Demo page here.

As per usual, any & all help gratefully received. TIA :)

+1  A: 

I've made a few changes to your code. Seems to work now. The main change was to recalculate only the row that has been changed, instead of recalculating every row every time. The total is still calculated from all totals, of course. I've also used event delegation to minimize the bound event handlers, which would have an impact on performance and resource usage for large tables.

jQuery(
    function($)
    {
        // threshold that defines at what quantity to use the discounted price
        var discountThreshold = 10;

        // bind the recalc function to the quantity fields
        // use event delegation to improve performance
        $("#frmOrder")
            .delegate(
                "input[name^=qty_item_]",
                "keyup",
                recalc
            );

        // run the calculation function once on every quantity input
        $("input[name^=qty_item_]").trigger("keyup");

        // recalculate only the changed row (and the grand total)
        function recalc(e) {
            // input field that triggered recalc()
            var
                $this = $(this),
                $parentRow = $this.closest('tr'),
                quantity = $this.parseNumber()[0],
                $usePrice = ((discountThreshold <= quantity) ? $("[id^=price_item_2_]", $parentRow) : $("[id^=price_item_1_]", $parentRow)) || 0;

            // recalculate the row price
            $("[id^=total_item_]", $parentRow).calc(
                // the equation to use for the calculation
                "qty * price",
                // define the variables used in the equation, these can be a jQuery object
                {
                    qty: $this,
                    price: $usePrice
                },
                // define the formatting callback, the results of the calculation are passed to this function
                function (s){
                    // return the number as a dollar amount
                    return "$" + s.toFixed(2);
                },
                // define the finish callback, this runs after the calculation has been complete
                function ($that){
                    // sum the total of the $("[id^=total_item]") selector
                    var sum = $("[id^=total_item_]").sum();
                    $("#grand_total").text(
                        // round the results to 2 digits
                        "$" + sum.toFixed(2)
                    );
                }
            );
        }
    }
);
Thomas
Hi Thomas, thanks for the input but that's not it unfortunately. I've updated the code to force quantity as an integer and put together a demo page.
da5id
@da5id: I've edited my answer to provide you with a working code snippet. It should work as you required now.
Thomas
Cheers Thomas, that works like a charm. I woke up this morning thinking I was going to have to approach it from a completely different angle, so I can't tell you how much time you've saved me. Really appreciate the length you went to. Thanks again :)
da5id
@da5id: Glad I could save someone's morning. ;)
Thomas