jQuery Calculation Plug-in: Making calculating easy...

Posted by Dan on Jan 23, 2008 @ 5:45 PM

I actually wrote this plug-in months ago, but only made passing mention about in on the jQuery mailing list. Since the topic of dynamic calculation came up again today on the mailing list, I thought I'd go ahead and officially announce the plug-in here.

My jQuery Calculation Plug-in was designed as a generic mathematical library to make it easy to do things like sum or average values that are displayed on the page. For example, to get the sum of all of the elements with the class of "price" you'd use:

alert( $(".price").sum() );

Since I did not want to restrict calculation to only form elements, the plug-in has helper method called parseNumber() which is called internally which parses a numeric value from an element. It can parse both form elements and normal HTML elements (like <div> or <span> elements.) In order to allow parsing of HTML elements that might contain additional formatting in the element, I'm using a regular expression of /\d+(,\d{3})*(\.\d{1,})?/g to parse the contents of the element to find the first thing that looks like a number. And don't worry, you can configure the regular expression if it doesn't meet your needs.

This plug-in actually gives you a lot of power. For example, let's say we have a form that looks like:

calc.plugin.cart

Wouldn't it be great if you could update all the calculations on the screen without writing a ton of code? Well, this is where the Calculation Plug-in really shines. The HTML for the table above is:

<table width="500">
<col style="width: 50px;" />
<col />
<col style="width: 60px;" />
<col style="width: 110px;" />
<tr>
    <th>
        Qty
    </th>
    <th align="left">
        Product
    </th>
    <th>
        Price
    </th>
    <th>
        Total
    </th>
</tr>
<tr>
    <td align="center">
        <input type="text" name="qty_item_1" id="qty_item_1" value="1" size="2" />
    </td>
    <td>
        <a href="http://www.packtpub.com/jQuery/book">Learning jQuery</a>
    </td>
    <td align="center" id="price_item_1">
        $39.99
    </td>
    <td align="center" id="total_item_1">
        $39.99
    </td>
</tr>
<tr>
    <td align="center">
        <input type="text" name="qty_item_2" id="qty_item_2" value="1" size="2" />
    </td>
    <td>
        <a href="http://jquery.com/">jQuery Donation</a>
    </td>
    <td align="center" id="price_item_2">
        $14.99
    </td>
    <td align="center" id="total_item_2">
        $14.99
    </td>
</tr>
<tr>
    <td colspan="3" align="right">
        <strong>Grand Total:</strong>
    </td>
    <td align="center" id="grandTotal">
    </td>
</tr>
</table>

In order to hook our form up so that all of the totals are automatically calculated on the fly, we just need to bind a function to the quantity fields to be triggered on each key press:

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

Our recalc() function looks like this:

function recalc(){
    // run the calc() method on each of the "total" fields
    $("[@id^=total_item]").calc(
        // the equation to use for the calculation
        "qty * price",
        // we now define the values for the variables defined in the equation above
        {
            // instead of using a static value, we use a jQuery object which grabs all the quantities
            qty: $("input[@name^=qty_item_]"),
            // now we define the jQuery object which reads in the "price" from the table cell
            price: $("[@id^=price_item_]")
        },
        // this function is execute after the calculation is completed, which allows us to
        // add formatting to our value
        function (s){
            // return the number as a dollar amount
            return "$" + s.toFixed(2);
        },
        // once all calculations are completed, we execute the code below
        function ($this){
            // now we get the sum() of all the values we just calculated
            var sum = $this.sum();

            // now that we have the grand total, we must update the screen
            $("#grandTotal").text(
                // round the results to 2 digits
                "$" + sum.toFixed(2)
            );
        }
    );
}

Well this code may look a little overwhelming at first, it's actually very easy to implement. You can see this example code in action on the Calculation Plug-in's home page.

The one big "gotcha" with using jQuery selectors as variables for the equations is that your selectors must return arrays of equal size. The calc() engine needs matching arrays, so that it can correct apply the calculations to each position in the array. For example, the above code actually translates to:

qty[0] * price[0] = total[0]
qty[1] * price[1] = total[1]

I think for the most part this should be a big deal, but I guess if you had a really strange layout trying to get your selectors to match up array items correctly could be programmatic. Unfortunately, I'm not sure there's a solution to that problem that doesn't involve a lot of complexity.

Run example code

Categories: JavaScript, jQuery

247 Comments

  • hi,
    this plug-in doesn´t work on IE 7.


    regards,
    Rui
  • @Rui:

    I just checked this in IE7 and it's working fine for me. Is there something specific that's not working for you?
  • hi, thks for the reply.

    if tested with your demo link and nothing (calculations) it´s working, but it works fine on FF.

    regards,
  • @Rui:

    I tested the code on my example page under IE7 and everything worked as expected. Perhaps you have something filtering/blocking content that's running under IE7.

    What errors are you seeing? I have tested the code under two different IE7 installations and the page works on both machines. It also works under IE6 for me.
  • ok.

    ...and what might be filtering/blocking ?
    i don´t have any firewall installed and i´ve stopped my anti-virus also.
  • if you want i´ll send you a print screen of it.
  • i´ll test on another IE7, ok ?

    regards,
  • @Rui:

    One culprit might be my check to see if Firefox is installed:

    bIsFirebugReady = (!!window.console && !!window.console.log);

    In normal circumstances, IE7 should not return true for that line--but perhaps you have something installed (like a debugger) which is causing the bIsFirebugReady check to be true.

    I'll certainly look into any errors you post for me.
  • ok, thks again for the reply.

    regards,
  • @Rui:

    Whatever info you can give me, I'll definitely try to fix the problem. It's just hard to address when you can't replicate and without more information on the error(s) you're getting, there's not a whole lot I can do. :)
  • Hi Dan,

    Thanks for the great plug-in. One question/feature request: It does not handle negative numbers. I think I was able to overcome this by changing the regex to allow an minus sign. Do you think this will suffice?

    reNumbers: /-?\d+(,\d{3})*(\.\d{1,})?/g

    I suspect that is why you have the regex as an option. My point in writing was merely to ask if my regex would work okay and allow negative numbers; and, if so, to suggest that you may want to make this the default. For example, on your demo page, if you enter a negative number, it actually sums or averages the absolute of it, which is a little misleading.

    Thanks again for the great plug-in!

    Dave
  • @Dave:

    That's definitely one of the reasons I saw the need to make the regex configurable. Plus, European number formatting is different from the US.

    Adding support for negative numbers was definitely an oversight on my part. The regex you have should work fine.

    As soon as I get a chance to do some more testing, I'll add the check for negative numbers to the next revision.

    I think the work I did last week to the sum() and avg() methods make it much easier to use. I'm always open to other suggestions as well.
  • @Dave:

    I updated the code this weekend and added support for negative numbers. Please test the new build and let me know how it works. I also added some callback methods for handling when the parseNumber() method can't find a numeric value in the element.
  • Hi Dan,

    Thanks for the nice plug-in.
    How to calculate the time can u pl give an idea

    Thanks
    Venkat
    :)
  • how do i do calculation like this: (qty * price) + fee. is there another event other than keyup? coz i use select box to trigger the calculation
  • @balboa:

    You can use whatever event you want to trigger the re-running of the $.calc() method--my example just uses the keyup. You could use my example pretty much verbatim, but just change the "keyup" event to the event you want to use (for a select box, you'll whant "change".)
  • Hey Dan,

    I've just started using your script, I like it a lot. But I'm working on a system which also needs to give a discount after a certain quantity number. I've been struggling with it for a while now, but I just can't get it right, could you help me with this?

    Thanks!
  • @Xevo:

    What's your code look like, is there an example I can see? Also, what problem are you having?
  • The sad thing is that I can not use this beatiful peace of code because whenever the form contains <input name="id"... jQuery throws an error 'z.indexOf is not a function'. I am not able to rename the input field because a lot of my CMS extensions depend on it :(
  • @Lukas:

    This isn't a jQuery problem, but an IE problem with form fields which have a name attribute value of "id" or "name".
    http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
  • Hi Dan

    Great plugin, it's really helped me a lot. Do you have any examples of how to work out the difference between two groups of fields? I know it should be simple but I'm stuck.

    e.g. I have a group with the class ".revenue" and one with ".cost" so I need to get the sum() of each and find the difference and put it in a 'total' field.


    cheers

    t
  • @Tom:

    Take a look at the example of the shopping cart and look at the code for the calc() method. It shows off similar functionality.
  • This is great. I now need to be able to submit a form and post the individual item totals and the grand total. It's quite clear I am a real javascript newbie so any help is greatly appreciated.
    Thanks, hal
  • @Hal:

    You should do the calculations on the server side. Never trust data coming from the client.
  • Thanks for this cool plugin. It was very easy to use!
    I have one question though. I'd like to format the totals (i want to group the digits).
    At the moment I'm using this:
      $("input[@name$=_x]").sum("keyup", "#som_month_x");
    I tried to convert this to something similar to the calc() example above, so that I'd
    have a cbFormat argument.
    What would be the best way to realize this? Thanks !!!
  • @Jonne:

    You can pass in an "oncalc" option, which is a call back that gets triggered after the calculation is performed. You can use this to format the value.
  • Great, and I figured out I should do that like this:
    $("input[@name^=input_]").sum({bind:"keyup",oncalc:myOnCalc}, "#som");
    Thanks !
  • Oops, I posted that it worked immediately when I figured out the oncalc callback was called. But now instead of the totals, nothing is displayed. I see that the oncalc method has two arguments, the value and options. But what should the method do? I tried returning nothing, true, false, s, and tried to put s in the totals field. But in all cases, the end result is an empty total field. What am I doing wrong? Thanks.
    function formatTotals(s, opt) { return s.toFixed(2); // test }
  • @Dan - Could you please provide an example of how to use the oncalc callback? Thanks!
  • @Stefan:

    If you look at the max() example in the demo, you could change that to something like:

    $("input[@name^=max]").max("keyup", {
        selector: "#numberMax"
        , oncalc: function (value, options){
            // you can use this to format the value
            $(options.selector).val("+" + value);
        }
    });

    This would add a plus symbol in front of the max value. If you reference "this" from inside the oncalc callback, it'll return a reference to the jQuery object of $("input[@name^=max]").
  • @Dan: Thanks a lot! It's working!

    One more question: I need to support the German number format for decimals where the "," is used as decimal point. Although I can change the regex for parsing the number format, I need to convert the comma into a dot before I can do any calculations. I can't figure out where to do the "replace()" without changing your plugin code. For the moment I changed your "parseNumber()" function by replacing this line

    v = v[0].replace(/[^0-9.\-]/g, "");

    with this line

    v = v[0].replace(/,/g, ".").replace(/[^0-9.\-]/g, "");

    I'm sure there's a better solution without the need to change your code.

    Thanks for you help!
  • @Stefan:

    Yeah, there's not a good way to handle that right now. What I would suggest is add an onParseNumber callback instead. You could then use that to convert the European format to US for the actual math operations.

    It would go something like this...

    Add this line above the onParseError in the defaults:

            // a callback function to run once when parsing a number
            , onParseNumber: null

    Now change the lines:

                        // clense the number one more time to remove extra data (like commas and dollar signs)
                        v = v[0].replace(/[^0-9.\-]/g, "");

    To:
                        // get the number
                        v = (jQuery.isFunction(options.onParseNumber)) ? options.onParseNumber.apply($el, [v[0]]) : v[0];
                        // cleanse the number one more time to remove extra data (like commas and dollar signs)
                        v = v.replace(/[^0-9.\-]/g, "");

    What you can do now is define the onParseNumber callback and have it return the value formatted with commas converted to periods.

    Add this to your source code (not the jquery.calculation.js code):

    $.Calculation.setDefaults({
        onParseNumber: function(value){
            return value.replace(/,/g, ".");
        }
    });

    I haven't test this, but it should work. It also gives you more flexibility to do other things in the future.
  • Dan, it works like a charm! Thank you very much!
  • I love this plugin. I'm using it on a clients site and it's working great, but I'm having trouble doing something that a commenter mentioned earlier.

    How would I get something like this to work?

    qty * price + fee

    I'd love to hear what you guys have to say, because I can't get it to work.
  • I am using your form and it works. But I am running into a problem that I can't solve as I am not that familiar with jquery. I use the grandTotal as a value in a form which will be submitted to a secure server. I've tried everything I can but can't seem to get this work. Is there any easy work around for this?
  • @Candi:

    You should never trust values sent from the client to the server--it's too easy to manipulate the values. When calculating values in the browser like this, it should be done simply to improve the UI. You should not be trusting this values, but should always verify data and do calculations on the server-side.
  • I love this plugin. I'm using your plugin in an online order form and it's working great. But this is the problem ;

    I want to use the grandTotal as a value of an input area. I've tried everything I can but can't work. Any idea :(
  • @Cenk:

    There shouldn't be an issues using an input field for value--as the examples show. I'd make sure you're using the most recent version:

    http://www.pengoworks.com/workshop/jquery/calculat...

    Also, while there shouldn't be any issues with using an input field, I'd advise against it, because there's no general reason to use. You never want to trust a value coming from the client like that--you'd want to do the calculations on the server anyway.
  • Thanks for responding. I ended up using a different calculating script. It's working great. It's too bad we can't use your plugin for quick calculating forms to be submitted to a merchant since it's so easy to implement. But I appreciate your time and energy!
  • @Candi:

    As I said, there should be no problem using an input element to update the value to. However, I would *never* be posting calculated values to a merchant that were generated via JavaScript. This makes your site extremely vulnerable to hacking. I hope you're not in any way trusting these values to be accurate.
  • @Dan :

    Thx for quick answer. But client side security is not a problem in this project.
    This is your(my) script part for grandTotal:
    $("[id^=grandTotal]").text(
                    // round the results to 2 digits
                        sum.toFixed(2) + "TL"
                    );

    and this the output:
    <td (or div) id="grandTotal">'grandTotal value'</td (or /div)>

    but I want this output:
    <input type="text" id="grandTotal" value="'grandTotal value'" name="whatever">
    or
    <td (or div) id="grandTotal">'grandTotal value'</td (or /div)>
    <input type="hidden" name="whatever" value="'grandTotal value'">
    Thanks a lot.
  • @Cenk:

    If your trying to update the value of an input element, you want to use val() instead of text()--that's your problem. What I'd recommend doing is something like this instead:

    $("input[name^='sum']").sum({
         bind: "keyup"
        , selector: "#grandTotal"
        , oncalc: function (value, settings){
            // you can use this callback to format values
            $(settings.selector).val(value.toFixed(2) + "TL");
        }
    });

    This would attach an event whenever the user finishes pressing a key in any input field that started with the id of "sum" and update the value in the #grandTotal element automatically. Maybe you don't need the "live" updating function--so this is just a suggestion.

    Also, instead of using the selector "[id^=grandTotal]" I'd just use "#grandTotal"--which is much faster and efficient.

    The syntax "[id^=grandTotal]" says look through *all* elements for ones that have an id attribute that starts with "grandTotal". That would match <div id="grandTotal1" />, <div id="grandTotal2" />, etc.

    On the otherhand, the syntax "#grandTotal" is just a shortcut for document.getElementById("grandTotal")--which is way faster and efficient.
  • @Dan:-) Thanks a lot again. It's working brillant :-)))
  • this is really a great plug-in. I'm now trying to develop an application but i need some help ...

    Is it possible to add some validation before the final result.
    To be more precise i need to check if the result will be between 200 and 500. If it is less than i need this app to show the result as 200 and if it is more than 500 to show result as 500. But if it is between 200 and 500 it should display the exact value

    for example
    20*3 the result should be 200
    51*8 the result should be 408
    100*6 the result should be 500

    i don't have lot of fields just two, the first which is changeable and the other is static

    Thank a lot in advance
  • @Benjo:

    If you're using the calc() method, just use the complete callback to trigger some validation (which you're have to handle manually.)

    $("[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: $("[id^=price_item_]")
        },
        // 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){
            // DO VALIDATION HERE
        }
    );
  • thanks lot. I added my validation at the point you showed me and it works great.
    Other question:
    Trying something out i tried to make two fields changeable, so no matter what field the user edit (like in this example qty and price) the total should change. Do i have to bind something to both fields like
    // bind the recalc function to the quantity fields
    $("input[@name^=qty_item_]").bind("keyup", recalc);
    and where to put this line of code for my other field???

    Second question:

    What if my table is generated dynamically based on a recordset. How to specify the IDs of those elements? i mean something like a shopping cart... If i have 10 items in my cart i would have 10 rows. Each row would have QTY field, price and total. How to make this plugin recognize how many rows there are and what are there ID's and do the math for each row.

    I'm sorry to have so much questions but i really like your plugin and i want to use it as much as possible.
    Thanks in advance.
  • @Benjo:

    If you want to recalc on each keypress, then you'd have to bind the behavior to any field where the user can press a key. Since jQuery is based on CSS selectors, you can use the comma as an "AND" selector, so something like this would bind to multiple elements:

    $("#id1, #i2").bind("keyup", recalc);

    As for the second question, you need to understand the CSS selector being used.

    The "input[name^=qty_item_]" (drop the @, it's been depreciated) says "Grab all input elements with a name attribute starting with "qty_item_".

    This means it would grab every element like:

    <input type="text" name="qty_item_1" />
    <input type="text" name="qty_item_2" />
    <input type="text" name="qty_item_3" />

    So, as long as your elements have a nomenclature like above, nothing in your jQuery code need to change.
  • Thanks a lot, it works!
  • support for European number format.

    Hi, I love ur plugin!
    I have trouble to get it working with the European number format.

    U described the chagnes for Stefan but the it seems it doesn't work with the current version anymore.

    can u please give me the changes I have to do in the current version?

    THX a lot!!
  • @Philipp:

    See this comment for how to use European formatted numbers:

    http://blog.pengoworks.com/index.cfm/2008/2/20/Wat...
  • I love ur plug in. But, how do I get price an item from db using select box?
  • Hi Dan!

    Got the same problem like stefan with the german/european comas, the output got every time points. I need 990,50 EUR not 990.5 EUR. How can I do that? I tried allready the hints of the other posts, but got no luck.

    Thanks
    Philipp
  • Thanks for this library. Works great.
    But here's a new issue. I have a time-entry system where people can enter their time worked for the day. There are several time entry fields on the form and they enter it in hh:mm format, so if someone worked on project A for an hour and 15 minutes, then they'd enter it as 1:15.  So I want a field on the bottom of the column that will add up the fields and show total time. So the calculation must be done base 60 and account for the colons.
    Any thoughts?
  • @John:

    That's basically outside of the scope of the concept of the calculation plug-in. Time calculations are a completely different beast altogether. You can get into days, months, years, etc.

    You're really going to want to create your own solution for your needs here. The calc plug-in is designed to help you solve generic math problems. I may eventually consider date/time functionality, but have no plans to do so currently.
  • Hi Dan,

    First off great plugin. 10 points for ease of use.

    I have come accross a bug. I noticed it on my site and after checking I get the same result on your demo page.

    If you go to the first demo (the sum demo) and in the 4 boxes put:
    10
    9
    5.1
    5.21

    The answer it gives is: 29.310000000000002

    I looked at the source code and am at a loss as to why it happens.


    Any ideas?
  • After placing this code in a blank page:

    var total = 0;
    total += 10;
    total += 9;
    total += 5.1;
    total += 5.21;

    alert(total);

    I get the same nuts result. Must be a javascript funny....
    I think total = total.toFixed(2); will solve my problem.
  • @rpcutts:

    This is actually a precision issue. Here's some information that describes the issue:
    http://bytes.com/topic/javascript/answers/518574-j...

    To see a simple example of the precision issue, copy the text "javascript:alert(0.7 + 0.1)" (without the quotes) into your address bar and press [ENTER].

    I'm sure you'll expect the answer to be 0.8, but instead you'll see the value is 0.7999999999999999.

    I may look at adding some logic to help make the results more predictable.

    However, you can resolve this issue by using the oncalc callback to simply format the number to the precision you want.
  • Yes I've been educated on the fun world of floating point.
    Sorry for all the noise.
  • @rpcutts:

    Last night I decided to add some precision handling to the code. If you download the new version of the code the sum() and calc() method should automatically round numbers to the correct precision.

    It does this by counting the max decimal places being used by the numbers and using that as a reference to figure out the precision.
  • I think I might misunderstand the application of this calculation tool.

    My desire is to have a form (particularly your quantity/item example) that does calculation on the fly and passes the final amount to a payment processor. From the comments I'm reading so far here, it appears best practice is NOT to use the returned amount via JavaScript, but rather, to do the calculation server-side.

    I freely admit I've got a lot to learn about JavaScript and DOM, and that I might simply have failed to grasp a concept or three.

    That said, how on Earth do I safely pass a calculated-on-the-fly total value to a hidden input field that is form-submitted?

    Thanks in advance.
  • @Jubal:

    You are correct--you should never trust values coming from JavaScript (aka the client.) All pricing information should come directly from a protect location (such as your controlled server.) If you were to accept dollar amounts coming directly from a hidden form field or from the user's browser, it would be very easy for a knowledgeable user to post whatever dollar amounts they wanted.

    The purpose of this plug-in is to help you with the task of building a better UI. Users like to see totals updated in real-time and this will help you easily build an interface to show totals get updated in real-time. However, you just shouldn't be trusting of these values.
  • I updated the to jquery 1.3.2 and jquery calculation 0.4 and the code broke. jquery 1.2.6 works fine with jquery calculation 0.4. Anybody else having this problem
  • Make sure you're not using old style attribute selectors (with the @ character)--this syntax no longer works in jQuery v1.3.x (it was depreciated in v1.2.x.)

    So, lines like $("input[@attr=...]") should be $("input[attr=...]").

    I've tested the plug-in with jQuery v1.3.x and it works fine. The example page is running v1.3.1 of the Google CDN.

    Lastly, make sure you're running the latest version of the plug-in.
  • It works now, thanks
  • Dan,

    I'm not able to get this to work. All I'm getting is sum() (not just sum, but all the functions) not defined.

    Here is my example.

    http://mercury.hamilton.edu/devmpstone/forms-pdf/c...?
  • @Mike:

    If you change:

    $(document).ready(function(){

    to:

    $(window).load(function(){

    Does it work?
  • Dan,

    No, it doesn't fix it.
  • Dan,

    There is a problem with your .js file.

    Downloaded the .min.js file and everything seemed to work.

    Might want to take a look at it.

    Best regards,

    Mike
  • Dan,

    If you've got time, could you take a look at:

    http://mercury.hamilton.edu/devmpstone/forms-pdf/e...

    Having trouble correctly calculating this very large table.

    Maybe/Hoping you've got an idea.

    Thanks.
  • @Michael:

    Could you be more explicit about the actual problem you're having?
  • Hi Dan,

    this is a great plugin, I really am appreciating it.

    I was wondering if you could help me with this, I am trying to do two calculations from the same fields, and have them both bind to one click event. I have been unsuccessful in getting it to work.
    any suggestions?

    Cheers
    -Keith
  • Sorry,

    didn't post my URL

    http://leftcoastgeek.com/calc/

    thanks!
  • @Keith:

    You've got your functions defined incorrectly, use this instead:

    function incSales(){
        $("#incSales").calc(
                "revenue * (margin / 100)",
                // define the variables used in the equation, these can be a jQuery object
                {
                    revenue: $("input[name^=annRevenue]"),
                    margin: $("input[name^=margin]")
                },
                // define the finish callback, this runs after the calculation has been complete
                function ($this){
                    // sum the total of the $("[id^=total_item]") selector
                    var sales = $this;

                    return sales.toString() + "M";
                }

        );
    }

    function incProfit(){
        $("#incProfit").calc(
                "revenue * margin",
                // define the variables used in the equation, these can be a jQuery object
                {
                    revenue: $("input[name^=annRevenue]"),
                    margin: $("input[name^=margin]")
                },
                // define the finish callback, this runs after the calculation has been complete
                function ($this){
                    // sum the total of the $("[id^=total_item]") selector
                    var sales = $this;

                    return "$" + sales.toString();
                }

        );
    }
  • Dan,

    that was just what I needed, Thank you!
  • Hi Dan,

    Can you please check my code? I'm a jquery nOOb but I did my best. Here's my code...

    <script type="text/javascript">
        var bIsFirebugReady = (!!window.console && !!window.console.log);

        $(document).ready(
            function (){

                // automatically update the "#totalSum" field every time
                // the values are changes via the keyup event

                $(".row").find(".sum").sum("keyup", $(".row").find(".totalSum"));

            }
        );
    </script>



    <table width="900" border="0">
     <tr id="tr_1" class="row">
      <td><input type="text" id="1_1" class="sum" value="2" size="2" /></th>
      <td><input type="text" id="1_2" class="sum" value="2" size="2" /></th>
      <td><input type="text" id="1_3" class="sum" value="2" size="2" /></th>
      <td><input type="text" id="1_4" class="sum" value="2" size="2" /></th>
      <td><input type="text" id="1_total" class="totalSum" value="" size="2" readonly="readonly" /></th>
     </tr>

     <tr id="tr_2" class="row">
      <td><input type="text" id="2_1" class="sum" value="2" size="2" /></th>
      <td><input type="text" id="2_2" class="sum" value="2" size="2" /></th>
      <td><input type="text" id="2_3" class="sum" value="2" size="2" /></th>
      <td><input type="text" id="2_4" class="sum" value="2" size="2" /></th>
      <td><input type="text" id="2_total" class="totalSum" value="" size="2" readonly="readonly" /></th>
     </tr>
    </table>

    What I wanted to do is that each <tr> will act as a "parent" so every row will have independent totalSum. I'm gonna use ASP:repeater which means all ID's of rows and textbox will be dynamically generated so I'll be relying on my "class" names.

    What I was trying to achieve is something like this:
    $(this).(".row").find(".sum").sum("keyup", $(this).(".row").find(".totalSum"));

    but of course it won't work - I can't nail the right syntax! :(

    Thank you for your help
  • @Marc:

    What you're needing to do is something like:

    $("#tr_1").find(".sum").sum("keyup", "#1_total");
    $("#tr_2").find(".sum").sum("keyup", "#2_total");

    Since you don't really want to do that for each row, you can make things dynamic:

    $("tr.row").each(function (){
      var n = this.id.split("_")[1];
      $(this).find(".sum").sum("keyup", "#" + n + "_total");
    });

    This will loop through each table row and run the run the appropriate sum() for each table row.
  • Hi
    Thanks for your plugin, I need to know if its possible to use this plugin with radiobutton and checkboxes ?
    for example we have a list of radio buttons that user can select them , then this plugin calculate them ?
    Thanks
  • @Farshad:

    You should have no problems using any type of form element. You may need to use the Field plug-in, but there should be no issues using any form element.

    You can get the Field plug-in here:
    http://plugins.jquery.com/project/field
  • I can use this plugin with radio buttons, but it will sum all the values of the radiobuttons, i want be able to sum the values of only selected radio buttons, how can i don that ?
  • @Farshad:

    I can tell you that it does work, but you will probably need to use the Field plugin (as I stated above) and without seeing code, I can't give you guidance.
  • For example look at this page :
    https://www.psd2html.com/order-now.html
    when you change the order details with radio buttons the total price will change too
  • Great plugin ! Is it possible to include a 'Square Root' in a function ?
    Thanks !
  • @Farshad:

    I know what you want and the calc plug-in will work, but you must use the field plug-in.
  • @Ben 58:

    Square rooting a number is a pretty specific task and would be much easier to just write specific code to do that. It's not a situation where this plug-in would really save you any coding.
  • Really appreciate your plugin. I'm having some trouble with the following:

    1. I add form elements on the fly and would like to sum their values, but .sum only seems to work with what's there when the page loads. I'm thinking there should be a way to use .live?

    2. I need to select the elements by both the beginning and end of their name or id. I'm dealing with names like product_nnn_id and product_nnn_value where the nnn varies and would like to sum all the product_nnn_value's. I'm sure there's a way to do this in the selector, but I can't find it.

    Thanks for putting this out there.
  • @jimjim:

    First, remember that the $.live() event handler only works with certain events. Many form-specific events aren't currently supported.

    Second, you can use $.live(), but you won't be able to use the help arguments (which automatically bind the sum() to field.) Instead you'll need to build the functionality manually, something like:

    var $sum = $(":input.sum").live("keypress", function (){
     $("#total").html($sum.sum());
    })

    (I didn't test the code, but something like that will work.)

    As for your selector problem, I'm not aware of a way to find dynamic values sandwiched like that.

    What I would recommend is just adding a class to each element such as "product_values". That will allow you to query the fields you need to sum by class name instead of the name attribute.
  • Thanks for a quick response. I think I'm close. Regarding the selector, I was looking for a way to select on everything but the dynamic values. What's listed below solves the selector issue. It does not however update my total. Any ideas?

    $(function() {
      var line_items = $("input[name^=opportunity[line_items_attributes]][name$=[value]]").live("keyup", function(){
        var sum = line_items.sum();
        $("#totalSum").val(sum);
      });
    });
  • @jimjim:

    Sorry for misleading you in my last post, but you won't be able to save the results of the selector in a variable since your results may change at any time. You'll either:

    1) Have to re-run the selector each time
    2) Maintain a separate queue of known input.

    Option 1 is the easiest, but it might be really slow depending on how many elements you're dealing with:
    $(function() {
        var selector = "input[name^=opportunity[line_items_attributes]][name$=[value]]";
        var line_items = $(selector).live("keyup", function(){
            var sum = $(selector).sum();
            $("#totalSum").val(sum);
        });
    });

    Option 2 is more work. It'll require you building a queue of known matching elements.
  • Ha! It works! I've added some to set the total initially and to update the total when I remove one of the fields. Won't be more than 5 or 6 fields and it seems plenty fast.

    FYI - using this with the Rails Complex Forms + JQuery example / pattern.

    Thanks again.

    $(function() {
      var selector = "input:visible[name^=opportunity[line_items_attributes]][name$=[value]]";
      var total = $(selector).sum();
      $("#totalSum").val(total);
      $(selector).live("keyup", function(){
        var total = $(selector).sum();
        $("#totalSum").val(total);
      });
      $("a:contains('remove')").live("click", function(){
        var total = $(selector).sum();
        $("#totalSum").val(total);
      });
    });
  • Just like Farshad Im trying to use this plugin with radio buttons, but can't get it to work. Im using the field plugin as instructed, but I can't seem to make anything work. Im trying to copy the quantity amount demo, but with radios...
  • hello, this is a great script, however im fairly new into jquery and what not, but i seem to be having the same issue as @jimjim. I am also creating the form dynamically and the fields created after loading don't pull in the calculation. what can i do to get this running? thanks for all the help!
    cameron
  • Hi

    Amazing plugin but still find it hard to get it do what i want.

    I want a form that calculates values of checkboxes en selectboxes.
    It should put different categories in a sub total and at the end it should calculate the grand total price.

    I got it so far that is calculates the sub total but somehow the grand total doesn't work. and also when i first load the pages it doesn't load the standard decision only when you click it

    Can someone help me on my way ?

    Url : http://web.productieserver.nl/martin/rekenModule/

    Javascript :

    $(document).ready(
        function (){

            $.Calculation.setDefaults({
                // Amerikaanse prijs formaat omzetten naar europees
                //reNumbers: /(-|-\$)?(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})?/g
                reNumbers: /(-|-\$)?(\d+(\.\d{3})*(\,\d{1,})?|\,\d{1,})?/g
                // define a procedure to convert the string number into an actual usable number
                , cleanseNumber: function (v){
                    // cleanse the number one more time to remove extra data (like commas and dollar signs)
                    // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
                    return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
                }
            });

            // optellen van Selectboxes
            $("select").change(function() {
              var total = 0;
              $("select option:selected").each(function() {
                total += parseFloat($(this).val());
              });

              $("#total_1").text(
                    total.toFixed(2).replace(/\./,',') + " EUR"
                );

            });

            // optellen van radio buttons
            $("input[type=radio]").click(function() {
              var total = 0;
              $("input[type=radio]:checked").each(function() {
                total += parseFloat($(this).val());
              });

              $("#total_2").text(
                    total.toFixed(2).replace(/\./,',') + " EUR"
                );

            });


            // Totaal uitrekenen
            $(".total").change(function() {
              var total = 0;
              $(".total").each(function() {
                total += parseFloat($(this).text());
              });

              $("#grandTotal").text(
                    total.toFixed(2).replace(/\./,',') + " EUR"
                );

            });

        }
    );
  • This line in version 0.4.07:
     var tmp = cbFormat.apply(this, [exprValue])
    is missing a terminal semicolon; which confuses javascript compressors. Adding the line terminator cures the "missing ; before statement" javascript error.
  • @Randy:

    Good catch. I try to always terminate lines with a semi-colon, but mistakes happen.

    Thanks for the report!

    I've corrected it in my source code. The fix will be in the next release.
  • Is there any way to change the price based on quantity - like if you buy 10 or more Learning jQuery books the price becomes 29.99? Seems like it should be easy but I haven't been able to get to work - thanks for the plugin
  • @Tim:

    The calc plug-in isn't designed to do all the work for you. It's just a helper library to help reduce the amount of code you have to write for repetative functionality. So this isn't something the calc plug-in has built-in.

    However, it's still easy to implement. All you need to do is monitor the quantity field and update your value based upon your pricing scheme.

    The calc plug-in reads the values in on each execution, so if you change the price the next time calc functions are run the correct price will be calculated.
  • I tried your solution for Mark (8/18/09).
    $("tr.row").each(function (){
    var n = this.id.split("_")[1];
    $(this).find(".sum").sum("keyup", "#" + n + "_total");
    });

    It works perfectly!

    The scenario that I am using it in is a little different. In that there are no input fields -- only spans, and I am using the class to calculate the sum. Now I am using this plug-in in conjunction with another, edit-in-place plug-in. What happens is that when a user clicks on the numeric value, an input field (with a class called "inplace_field") is dynamically added inside of the .sum span. This, quite predictably causes the newly entered number to not be registered by the code. I am looking for a way to tell the code to look for the child(ren) of .sum also, and if it exists use that as well in the calculation. Thank you.
  • I need a little help if you don't mind.

    In the following code everything works, except the callback function (oncalc). It's never applied.

    $(document).ready(function (){
    $('input.BilanExploitationPM_BilanSynthetiquePM_EnActif').sum({
    bind: 'keyup',
    selector: 'input#Total_BilanExploitationPM_BilanSynthetiquePM_EnActif',
    oncalc: function (settings, value) {
    $(settings.selector).val+(value.replace(/\./g, ','));
    }
    });
    });

    Is it even possible to use a callback function with the sum() method?

    Thanks for your help.
  • The "+" after "val" is just a typo. Sorry. The question is still on.
  • I'm stupid, stupid, stupid.

    I wrote "oncalc: function (settings, value)" instead of "oncalc: function (value, settings)". I don't how I ended up doing this as I really thought I copy/pasted the code.

    You can delete this post and both the previous ones.
  • I am using the following code to calculate the total in all elements with class "sum"

                      $(function()
                      {
                                            $("tr.row").each(function (){
                                            var n = this.id.split("_")[1];
                                            $(this).find(".sum").sum("keyup", "#" + n + "_total");
                                            });

                      });

    The problem arises when an input is added dynamically to the element with class "sum".

    This works fine:
    <tr id="tr_#myReport.currentRow#" class="row">
    <td>
    <span class="sum" id="qp_#myReport.Uid#" >#DepositQP#</span>
    </td>
    <td>
    <span class=" sum" id="rg_#myReport.Uid#">#DepositReg#</span>
    </td>
    <td>
    <span class="totalSum" id="#myReport.currentRow#_total"></span>
    </td>
    </tr>

    But when an input is added within one of the "sum" spans, predictably, it fails:

    <tr id="tr_#myReport.currentRow#" class="row">
    <td>
    <span class="sum" id="qp_#myReport.Uid#" >#DepositQP#</span>
    </td>
    <td>
    <span class=" sum" id="rg_#myReport.Uid#">#DepositReg#
    <form class="inplace_form">
     <input class="inplace_field" value="inplace_value">
    </form>
    </span>
    </td>
    <td>
    <span class="totalSum" id="#myReport.currentRow#_total"></span>
    </td>
    </tr>

    Any suggestions to make it work?

    Thanks.
  • @Rhapsody:

    When you add new rows, you'll also need to invoke the $.sum() call on the new rows.
  • Thanks for your response Dan. It is invoked for each row, but when a dynamic input field is added to the "sum" elements, it does not register it, because the newly added field is an element within "sum" class. Here is a demo page: http://intranet.gcitexas.com/demo.htm. Perhaps that would help my explanation.
  • @Rhapsody:

    This would be the expected result with jQuery. Calling a selector on the page only effects the elements in the DOM at the time when you ran the initial code, future elements would be unaffected.

    So, my comment still remains the same--whenever you add new fields, you're going to need to invoke the $.sum() method on those fields.
  • Hello Dan,

    Great plug in. If I wanted to sum all the values within the page that had the id="item-total-#" across the page. Where # is the Item number.

    The expected result would be
    #grandTotal1 = 11
    #grandTotal2 = 22

    Could you please provide some tips as to how I would be able to achieve my expected results using your plug-in?

    Thanks in advance,
    Derek

    <table>
    <tr>
    <td>Item 1 Total</div></td>
    <td><div id="grandTotal1">0</div></td>
    </tr>
    <tr>
    <td>Item 2 Total</div></td>
    <td><div id="grandTotal2">0</div></td>
    </tr>
    </table>

    <h1>Shipment 1</h1>
    <table>
    <tr>
    <td>item 1 total</td>
    <td><div id="item-total-1">1</div></td>
    </tr>
    <tr>
    <td>item 2 total</td>
    <td><div id="item-total-2">2</div></td>
    </tr>
    </table>

    <h1>Shipment 2</h1>
    <table>
    <tr>
    <td>item 1 total</td>
    <td><div id="item-total-1">10</div></td>
    </tr>
    <tr>
    <td>item 2 total</td>
    <td><div id="item-total-2">20</div></td>
    </tr>
    </table>
  • @Derek:

    The ID attribute on an element must be unique--so by repeating ID values you're creating invalid HTML and jQuery will only find the first matching ID.

    If you change the ID attributes above to the CLASS attribute, then you should be able to do:

    $("item-total-1").sum("keyup", "#grandTotal1");
    $("item-total-2").sum("keyup", "#grandTotal2");

    -Dan
  • Thanks for the quick response Dan.

    I've changed my item-total IDs tags to CLASS tags and included the jQuery statments that you have provided, but the #grandTotal IDs do not get updated with the sum. Any ideas as to what I may be doing wrong?

    Thanks,
    Derek

    <table>
     <tr>
     <td>Item 1 Total</div></td>
     <td><div id="grandTotal1">0</div></td>
     </tr>
     <tr>
     <td>Item 2 Total</div></td>
     <td><div id="grandTotal2">0</div></td>
     </tr>
     </table>

     <h1>Shipment 1</h1>
     <table>
     <tr>
     <td>item 1 total</td>
     <td><div class="item-total-1">1</div></td>
     </tr>
     <tr>
     <td>item 2 total</td>
     <td><div class="item-total-2">2</div></td>
     </tr>
     </table>

     <h1>Shipment 2</h1>
     <table>
     <tr>
     <td>item 1 total</td>
     <td><div class="item-total-1">10</div></td>
     </tr>
     <tr>
     <td>item 2 total</td>
     <td><div class="item-total-2">20</div></td>
     </tr>
     </table>
  • Hi Derek

    Thank you for your excellent plugin. I'm using it on a conference website to calculate registration costs (yes, and cleaning the input server side).

    I'm try to apply a discount based on the number of people attending and have this working correctly, however, I can't get the discount to update after it has been triggered. I.e. The total quantity gets to 10, and the discount is applied correctly, but then if the total qty value is reduced the discount isn't being updated. Everything else, the totals, etc, is working fine. This is the code:

    // FORM CALCULATION

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

    function recalc(){
        $("[id^=conf_total_]").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^=conf_qty_]"),
                price: $("[id^=conf_cost_]")
            },
            // 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^=conf_total_]") selector
                var sum = $this.sum();

                $("#conf_subtotal").text(
                    // round the results to 2 digits
                    "$" + sum.toFixed(2)
                );
            }
        );
        // Discount
        $totalqty = $("input[name^='conf_qty_']").sum("keyup", "#conf_discount_qty_total");
        $totalqty_value = $('[name=conf_discount_qty_total]').val();
        if($totalqty_value >= 10) {
            $("[id^=conf_discount_group]").calc(
                // the equation to use for the calculation
                "price - (discount * price)",
                // define the variables used in the equation, these can be a jQuery object
                {
                    discount: .05,
                    price: $("[id^=conf_subtotal]")
                },
                // 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);
                }
            );
        }
    }
  • @AdamG:

    I'm not sure I understand your question. You have code that looks like it's specifically preventing the discount from being applied if less that 10:

    if($totalqty_value >= 10)
  • Hey Dan,

    I just wanted to let you know that I leveraged your example in the calculation plug-in main page to solve my problem.

    $("#idTotalTextSum").click(
        function (){
        // get the sum of the elements
        var sum = $(".textSum").sum();

        // update the total
        $("#totalTextSum").text("$" + sum.toString());
                    }
    );

    Thanks again for this awesome tool.

    -Derek
  • Hello, I was wondering... is there a way to store that final grandTotal value in a php variable so that I can pass that along through forms and such ? Thank you very much, great support.
  • @Dan:

    You should do that type of calculation in PHP. You should never trust calculations coming from the client-side--they are too easy to manipulate.
  • I agree, however I already spent a lot of time implementing your method in my little project for school. No security issues will occur because this project is to be used only locally. So, can I please hear a tip or a suggestion on how to catch that grandTotal variable. Thank you and congrats for your great support !
  • @Dan:

    You can use the complete callback to update a hidden form field. In the example above, you'd change the code:

        function (s){
          // return the number as a dollar amount
          return "$" + s.toFixed(2);
        },

    to something like:

        function (s){
          var value = "$" + s.toFixed(2);
          // update hidden form field
          $("#grandTotal_field").val(value);
          // return the number as a dollar amount
          return value;
        },
  • How do I handle a web form whose sum equation includes a term that is a product of two html fields? Like this $("#a, #b, #c").sum where there is no actual #b element, instead there are #d and #e, which have to be multiplied together.

    I can create an otherwise unneeded #b subtotal element (perhaps hidden), but the keyup event is never produced from it. The elements producing keyup are #d and/or #e, and the sum method is not listening to them. Of course, tabbing through one of the registered fields works, but until then, a user sees no change in the sum.

    Also, the addition of a 'multiply' method would be more convenient than setting up 'calc()'
  • I added an event trigger to the 'finish callback' of 'calc()':

    $('#a').trigger('keyup'));

    Where #a is one of the elements registered in sum().  The calc() I'm referring to is used to multiply #d x #e.
  • @Randy:

    You wouldn't be able to use the sum() method to do what you want. You'd need to use the calc() method.

    Just as a reminder, these are just helper functions to help with the most common tasks. There are times when just writing custom code is going to be the best route to go. However, you should be able to do what you want with the calc() method, just make sure to use the appropriate parenthesis in your equation (i.e. "a + (d * e) + c".)
  • Quick question - I would like to update not only quantity * price in my invoice lines, but brutto value and vat value as well (per invoice line) - how can I approach this?

    Tried something like this (not working properly though)

    function recalc() {

      //netto_value
      $("[name$='[netto_value]']").calc(
          "qty * price",
      {
        qty: $("input[name$='[quantity]']"),
        price: $("[name$='[netto_price]']")
      },
          function (s) {
            return s.toFixed(2) + " PLN";
          },
          function ($this) {

            var vat_value = parseFloat($("[name$='[netto_value]']").val()) * parseFloat($("[name$='[vat_rate]']").val());
            var brutto_value = vat_value + parseFloat($("[name$='[netto_value]']").val());
             $("input[name$='[vat_value]']").val(vat_value);
            $("input[name$='[brutto_value]']").val(brutto_value);


          }
          );

    }
  • @Błażej:

    Just write a separate call to the calc() method for the other fields.

    If you're really want to update the values on when this particular calc() method is running, then you'll need to use a nomenclature for your fields that allow you to easily grab the correct corresponding fields for the current row.
  • thanks 4 that great plug-in it really helps a lot
    i have a question about this plug in
    i am trying to use it with quantity and price
    put the problem is that i am adding form elements of the quantity and price by java script and they are incrementing like q1,p1-----q2,p2...etc
    i am wondering how can i make the calculation plug-in read the added field coz it only reads the ones added by HTML
  • @Tarek:

    All you need to do is use jQuery's native live() method and manually call the method you want. You can not use the calc's native binding functions, unless you bind the new fields you add via JS.
  • how can i deduct number from the total??
  • @Tarek:

    You'll need to use the calc() method--or just manually perform the math on a callback.
  • I am trying to apply a 50% quantity discount on subsequent items if the total quantity of items is greater than one, and have one of the highest priced item not included in the discount. For example,

    1 - Item 1 - $100
    1 - Item 2 - $100
    2 - Item 3 - $120
    1 - Item 4 - $120
    0 - Item 5 - $140

    So, (100+100+120+120) / 2 + 120 = 340. I am trying to find the max price of only the item which has a quantity greater than zero. Then I could ((total - max) / 2) + max. But the closest I've come is the code below.

    Is there a way to find the max price of items with a quantity?

        // define the finish callback, this runs after the calculation has been complete
        function ($this)
        {
            var total_qty = $("input[name^=qty_item_]").sum();
            var max_price = $("[id^=price_item_]").max(); // this will take the max price of all items regardless of the quantity
            if (total_qty > 1)
            {
                var sum = (($this.sum() - max_price) / 2) + max_price;
            }
            else
            {
        // sum the total of the $("[id^=total_item]") selector
                var sum = $this.sum();
            }

            $("#grandTotal").text(
            // round the results to 2 digits
            "$" + sum.toFixed(2)
            );
        }

    Thanks.
  • @Pasquale:

    There's no built-in way to do this. The goal of the plug-in is to simplify more common tasks. For more complicated issues like this you're always going to have to rely on manually coding and solutions.
  • Is there a way to calculate percentages with this plug-in as easily as using $().sum?

    In plain English, I want to do this:

    Subtotal + x% Overhead = Adjusted Total
    or
    100 + 8% = 108

    The subtotal is already being calculated by your plug-in (thank you!) and the percentage number needs to be a text input field. The adjusted total is what I'd like to have calculated on-the-fly with your plug-in.

    Thanks again for the great plug-in! I'm one percentage calculation away from finishing my first project with it. :-)

    -Matt
  • @Matt:

    Just use the calc() method to perform the calculation.

    -Dan
  • How do I get the calc method to only pickup values which have a dollar sign next to them.

    If I have a label with

    $150

    the calculation works fine.

    If I have a label of

    Stock No. 12-1000 $150

    the parseNumber picks up the 12. How can I get it to pickup the $150? I believe it is in the Regular Expression but I am not sure if this is the best approach. I haven't been able to come up with a Regular Expression that parses the $150 from this span.

    Thanks,

    Rob
  • @Rob:

    Instead of mucking with the regex, I'd recommend just putting the price in it's own <span>, that way the default parser can find it.
  • hi, good plugin!
    I'm writing a script like the example shown in the demo where All of the "Total" values (Including the "Grand Total") are Automatically Calculated using the calc () method.

    But I have some fields in which to apply the equation qty * price, and others where I want to do other operations .. you can tell me how? thank you very much
  • Hi,

    i have found your plugin and i red the documentation provided and this blog page, but i didn't found (maybe i am blind) what i need.

    I have a table with X rows and Y columns, with Z fields each row.

    I need to sum all values in the same row with auto-update.
    values are like (php code):
    <input size="1" name="oreImpiegato[' . $impiegato["ID"] . '][' . $index . '][mattina]">

    The problem is that i do not know before the sql query how many rows i will have, so i need something like (given ID = 42):
    $("input[name^=';oreImpiegato[42]']").sum("keyup", "#totalOreImpiegato[42]");
    if necessary i can set up an ID for each <input> like "oreImpiegato_42_1", "oreImpiegato_42_2" and so on.

    is there a way to give to javascript an argument and use that instead of writing down all the possible functions?

    thanks
    d.
  • @Daniele:

    The CSS selector input[name^=';oreImpiegato[42]'] says: Get every input element with a name that begins with ";oreImpiegato[42]". So as long as every form field starts with that convention, it'll select all the fields starting with that name attribute.
  • Daniele Palumbo's Gravatar
    Daniele Palumbo
    @Dan:

    Yes thanks for this first hint but i was not so clear in my explanation.

    I have, for example, oreImpiegato[42][1], oreImpiegato[42][2] ..., oreImpiegato[9][...], oreImpiegato[12][...] and so on.
    i have a double index, the first identify the row, the second the column.

    i do not know how many rows i will get until i make the query to sql, and the index (ID, in the first example 42) is not ordered.

    i hope i explained well the problem this time ;)

    thanks
    Daniele
  • @Daniele

    If I understand this correctly, you want to be able to sum each dynamic row created, for example:

    Row 1 - <input name="oreImpiegato[42][1]" /> <input name="oreImpiegato[42][2]" /> <input name="totalSum42" id="totalSum42" />

    Row 2 - <input name="oreImpiegato[9][1]" /><input name="oreImpiegato[9][2]" /> <input name="totalSum9" id="totalSum9" />

    Row 3 - <input name="oreImpiegato[12][1]" /><input name="oreImpiegato[12][2]" /> <input name="totalSum12" id="totalSum12" />

    Since the rows are dynamic via a database query, you could loop through the query results to output the required jQuery within the document.ready like you loop and output for the input tags, for example:


    $("input[name^=oreImpiegato[42]]").sum("keyup", "#totalSum42");

    $("input[name^=oreImpiegato[9]]").sum("keyup", "#totalSum9");

    $("input[name^=oreImpiegato[12]]").sum("keyup", "#totalSum12");


    Replace 42, 9, 12 with the variable being used for the row ID.
  • hello,
    is it possible to do like this calculator-simulator (http://www.midocar.com/reservation1.php) with this jQuery?
    the results show only if all fields are checked :)
    thanks for any help.
  • hi Dan,

    thanks for your plugin, it's really helpful and powerful.
    but how i do filtering with your plugin?

    i got 2 textbox, 1 is for text input, another 1 is for amount input. i only can accept text input with the text length is either 5 or 6.

    then i got 7 checkbox to indicate 7 days in a week. if tick 1 day then amount = amount * 1, if tick 2 days then amount = amount * 2.

    and i got 1 combobox to indicate "Single" or "Double". if "Single", i no need any multiply, if "Double" then i need double up the amount.

    so let's say my text input is "qwert" and amount input is "2", then i tick Monday, Tuesday and Wednesday, and select "Double", my amount is 2 * 3 days * 2 = 12.

    if text input is "qwer" and amount input is "2", then i tick Monday, Tuesday and Wednesday, and select "Double", my amount is 0 because length of text input 4 only, what i needed is 5 or 6.

    hope you can understand my question and let me know your plugin can solve my question or not. currently i'm write a Javascript for this calculation. but i hope can use your jQuery plugin to simplified my coding.

    thanks in advance.
  • @CH:

    While you can probably hack together a solution using the plug-in, the plug-in is designed to help w/very structured and straightforward calculations. It'll be much cleaner to just build your needed functionality from scratch. The plug-in isn't really going to help you much.

    If you're really insisting on using the plug-in, the trick is going to be updating a hidden form field for the checkboxes and select boxes with values. For example, you'd update a hidden form field for the total number of checkboxes checked so you can use that in the calculation.

    However, like I said, I'd just build the logic from scratch since the code is so specific to your UI.
  • I'm trying to adopt the script for a recipe calculator. But it does not work... :( Any idea why this is not calculating right?
    HTML
    How much Portions`? <input type="text" id="portionen" value="10" />
    <ul>
    <li><span class="menge"><span class="qty" title="250">250</span> ml</span> Sahne</li>
    <li><span class="menge"><span class="qty" title="2">2</span></span> Eigelb</li>
    <li><span class="menge"><span class="qty" title="20">20</span> g</span> Vanillezucker</li>
    <li><span class="menge"><span class="qty" title="50">50</span> g</span> Erdbeeren</li>
    <li><span class="menge"><span class="qty" title="200">200</span> g</span> Erdebeermarmelade</li>
    <li><span class="menge"><span class="qty" title="20">20</span> g</span> Zucker</li>
    </ul>


    $("input#portionen").bind("keyup", recalc);

    function recalc(){
    $(".qty").calc(

        "portionen * qty",
        // define the variables used in the equation, these can be a jQuery object
        {
            //portionen: $("#portionen"),
            //qty: $(this).attr("name")
            portionen: $("#portionen"),
            qty: $(this).attr("title")
        },
        // define the formatting callback, the results of the calculation are passed to this function
        function (s){
            return s;
        }
    );
    }


    Any help is appreciated! ;)

    Thanks in advance and regards Sascha
  • @Sascha:

    The objects in the calculation must map to a jQuery object--which $(this).attr("title") does not.

    You really don't even need the calc plugin for this. I just use straight jQuery:

    $("#portionen").bind("keyup", function (){
        var portion = parseInt($.trim($(this).val()), 10);
        $(".qty").each(function (){
            var $qty = $(this);
            $qty.html( $qty.attr("title") * portion );
        });
    });
  • Ah! I see thank you very much for the insight. This is perfect! ;)
  • I'm having trouble working out how simple division may be carried out. Any pointers would be gratefully received.
  • Im new to jquery and having a little trouble figuring this out. How and what can I do to add an average bid feature to a table? I dont know were to start!
  • Hi, I hope u can give me a little help
    i'm using this function

    function recalc(){
        $("[id^=JQprezzoUnita_]").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[id^=JQunita_]"),
                price: $("input[id^=JQprezzo_]")
            },
            // 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);
            }
        );
        $("[id^=JQprezzoSconto_]").calc(
            // the equation to use for the calculation
            "qty * price-(((qty * price)/100)*sconto)",
            // define the variables used in the equation, these can be a jQuery object
            {
                qty: $("input[id^=JQunita_]"),
                price: $("input[id^=JQprezzo_]"),
                sconto: $("input[id^=JQsconto_]")
            },
            // 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^=JQprezzoUnita]") selector
                var sum = $this.sum();

                $("#JQimponibile").text(
                    // round the results to 2 digits
                    "€" + sum.toFixed(2)
                );
                $("#JQhidImponibile").val(
                    // round the results to 2 digits
                    sum.toFixed(2)
                );
            }
        );
    };
    if I use it with a dinamic jquery <td><input> creator with .bind() command its work fine with all browser

    but if i create the input in server side with PHP
    es:
    <td align="center"><input type="text" id="JQprezzo_1" size="8" name="n_art1-prezzo" value="0.00" onclick="recalc();"></td>
    <td align="center"><input type="text" id="JQunita_1" size="2" name="n_art1-vendi" value="0.00" onclick="recalc();"></td>
    <td align="center"><h1 id="JQprezzoUnita_1"></h1></td>

    it doesn't work in IE (i have tryied with IE7 on win xp, IE8 on XP and win7)
    in all others browser its work well (crome, ff,safari,opera)

    can you give me some hint ?
    thanks a lot

    daniele
    ps. sorry for my english.
  • apparently i have solved it with

    $(function(){
        $("[id^=JQprezzo_]").bind('keyup', recalc);
        $("[id^=JQunita_]").bind('keyup', recalc);
        $("[id^=JQsconto_]").bind('keyup', recalc);
        $("[id^=JQiva_]").bind('keyup', recalc);
    });
  • Hi Dan & thanks for an excellent plugin. You truly have the patience of a saint answering all our questions.

    I am trying to code a calculator that uses a different price based upon the quantity entered. One price for quantities over 10, and another for quantities under. This is the code I'm using, but I can't get it to work. Any help would be very much appreciated.

    function recalc() {

      $("[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_]"),
          {
            if (qty > 10) {
              price: $("[id^=price_item_2_]")
            } else {
              price: $("[id^=price_item_1_]")
            }
          }
        },

        // 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)
          );
        }

      );

    }
  • Solved it! Posting the solution here incase it's of use to anyone else:

    function recalc() {

      var $quantity = $("input[name^=qty_item_]").val();
      var $threshold = 10;
      if ($quantity < $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: $quantity,
          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)
          );
        }

      );

    }
  • Spoke too soon :( The above 'solution' doesn't work as it sets the price for all subsequent fields based on the first. Help!
  • I've messed around with the code a bit more, but still can't get it to work the way it I want it too. I've put together a demo @ http://calc.splendidprojects.com/
  • @David:

    The easiest way to resolve this problem is w/a hidden field. What you'll need to do is add an event trigger to your quantity field and update a hidden form field with the price to use based upon the qty. Then you just reference the hidden price field in your equations.
  • I'm having a REALLY hard time implementing radio buttons, especially since there isn't any solid example of whats involved. I've read through all the comments, and I understand that I need the Field plugin, which I'm using, but my total is still adding up each radio value, and it actually overwrites the complete total calculated elsewhere.


    Here's my jQuery Code:

    <script type="text/javascript" src="jquery.min.143.js"></script>
    <script type="text/javascript" src="jquery.calculate.js"></script>
    <script type="text/javascript" src="jquery.field.min.js"></script>

    <script type="text/javascript">
        $(document).ready(function (){
            $("input[name='delivery']").fieldArray();
            $("input[name='delivery']").sum('click', '#grandtotal');

            $("#quantity").bind("keyup", recalc);
            recalc();
        });

        function recalc(){
            $("#grandtotal").calc(
                "qty * price",
                {
                    qty: $("#quantity"),
                    price: $("#price")
                },
                function (s){
                    // return the number as a dollar amount
                    return "$" + s.toFixed(2);
                },
                function ($this){
                    var sum = $this.sum();
                    $("#grandtotal").text(
                        // round the results to 2 digits
                        "$" + sum.toFixed(2)
                    );
                }
            );
        }
    </script>


    Here's a skeletal version of my HTML, including all things that need adding, multiplying:

    <li>
        <label>Quantity</label>
        <input type="text" name="qty" id="quantity" value="1"/>
    </li>
    <li>
        <div id="price">$7.25</div>
    </li>


    <li class="radio">
        <input type="radio" name="delivery" value="2.48"/>
        <label>Letter Mail (5-7 business days): $2.48</label>
    </li>
    <li class="radio">
        <input type="radio" name="delivery" value="14.98"/>
        <label>Express post (next day): $14.98</label>
    </li>
    <li class="radio">
        <input type="radio" name="delivery" value="31.53"/>
        <label>Priority couriers (next morning): $31.53</label>
    </li>



    <div id="grandtotal">
        $7.25
    </div>



    What I want, is (quantity * price) + shipping

    but, when I select any shipping option, it returns the total as $48.99 (which is all three radio values summed up), and its not even adding that on TOP of the quantity*price, its completely overwriting it.



    I must be doing this completely wrong, please help!!
  • Hey Dan (or anyone else for that matter), disregard my previous comment, but I'm still very stuck.

    Check out this URL please

    http://stayawake.ca/sandbox/Calendar/

    As you can see, it is calculating the total of the first shipping option, even though it is unchecked, and of course, I can't for the life of me figure out the proper code/syntax whatever to update the total when a user selects a shipping option.

    I need some wisdom!!
  • @Jaime:

    The problem is you're not filtering out the selected radio element. Try this instead:

    $("#grandtotal").calc(
        "(qty * price) + shipping",
        {
            qty: $("#quantity"),
            price: $("#price"),
            shipping: $("input[name='delivery']:checked")
        },
        function (s){
            return "$" + s.toFixed(2);
        }
    );

    (You also don't need the other callback.)
  • Hi Dan, Thanks for plugin.

    But can you explain some moment for me?
    For example I have some input elements with price attributes. In parseNumber function I see following string

    sMethod = ($el.is(":input") ? defaults.useFieldPlugin ? "getValue" : "val") : "text"),

    Can you add an option to plugin to specify function to get values, for price attribute it might be .attr('price')

    Or give any ideas how to retrieve sum for attributes different than 'value'
  • @Roman:

    There's no native way to override the way the parseNumber() method gets the value. The only way to do it would be to replace the $.fn.parseNumber() method with your own function.

    It's certainly a good idea to add a way of overriding this method of getting the value--especially now that HTML allows for custom data attributes. I'll add this next time I work on the source code.
  • @Dan

    Thanks Dan for your response.
  • Dan, Great plugin!

    I'm trying to achieve the following but don't know Jquery well enough to implement it.

    I've knocked up a demo page to demonstrate a rough version of what I have in mind. Please refer to it to see if you can make sense of my thinking.

    http://www.think-telecom.com/test.php

    Slider 1 reprents units or a quantity ranging from 1 - 15.
    Slider 2 represents the contract term, minimum 12 months up to 36 months.

    I want to multiply the units by the contract term. This would be straight forward if the contract values were all the same but unfortunately the prices become cheaper the longer a client signs up.

    Example
    1 -12 month contract costs £11.00 per month
    13-24 month contract costs £9.00 per month
    25-36 month contract costs £7.00 per month

    I am completely new to Jquery/ Javascript and wondered if you could shed some light on using an if/ else statement? This is the first syntax I've written and I don't know what I'm missing to get it to work.

    $(document).ready(
            function (){

                // bind the recalc function to the quantity fields
                $("input[name=calc]").bind('change', recalc);
                // run the calculation function now
                recalc();
            }
        );

        function recalc(){
            $(".grandTotal").calc(
                // the equation to use for the calculation
                "(units * term)",

                if (term == 12) {
                    $(".grandTotal").calc ("units * x");
                },
                else if (term < = 24) {
                    $(".grandTotal").calc ("units * y");
                },
                else (term > = 24) {
                    $(".grandTotal").calc ("units * z");
                },

                // define the variables used in the equation, these can be a jQuery object
                {
                    units: $("#units"),
                    term: $("#term"),
                    x: $("11"),
                    y: $("9"),
                    z: $("6")
                },
                // define the formatting callback, the results of the calculation are passed to this function
                function (s){
                    // return the number as a sterling 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();

                    $(".grandTotal").text(
                        "£" + sum.toFixed(2)
                    );
                }
            );
        }


    The calculator works perfectly with the below code removed, apart from the fact it will only calculate off one fixed price.

    if (term == 12) {
                    $(".grandTotal").calc ("units * x");
                },
                else if (term < = 24) {
                    $(".grandTotal").calc ("units * y");
                },
                else (term > = 24) {
                    $(".grandTotal").calc ("units * z");
                },

    I really hope you help me to get this working because I don't know where else to turn.

    Cheers,

    Chris
  • @Chris:

    Using the calculate plug-in in this context is really overkill. You could just as easily bind behaviors and generate the calculation on the fly.

    However, if you want to use the calculate plug-in, what you'd need to do is have a hidden form field that you used to store the pricing. So instead of:

    // the equation to use for the calculation
    "(units * price)",

    // define the variables used in the equation, these can be a jQuery object
    {
     units: $("#units"),
     price: $("#price"),
    },

    What you'd need to do then is update the a hidden field w/an id of "price" whenever the #term element is changed.
  • Thanks for the speedy response Dan,

    As mentioned, I'm new to this so it comes as no surpise that I'm over killing the concept.

    Do you have an example of binding the behaviours to generate the result on the fly? I'm all for the path of least resistence but the problem is I don't know how go about writing the code.

    If I carry on with the hidden fields you mentioned, I struggle with understanding how I'd reference it. In the below example of the HTML, I have 3 x hidden fields representing the 3 different price structures. Is this what you had in mind and if so how would I dip into the relevant price based on the the term selected? Keeping in mind its one value for clients signing up for 12 months, another for signing up between 13 & 24 months etc?

    <form action="#" method="post">

    <p>
    <input type="range" name="calc" id="units" min="1" max="15" value="0.1" />
    <label for="extensions" style="float:left; margin:33px 0 0 6px">extension(s)</label>
    </p>

    <p>
    <input type="range" name="calc" id="term" min="12" max="36" value="0.1" />
    <input type="hidden" name="calc" id="price" value="£11.99" />
    <input type="hidden" name="calc" id="price" value="£9.99" />
    <input type="hidden" name="calc" id="price" value="£6.99" />

    <label for="contract" style="float:left; margin:33px 0 0 6px">months</label>
    </p>

    </form>

    Apologies if I'm making life difficult but I'm keen to get this nailed.
  • Hi I need help with very simple calculation.

    I have a form and I want the grand total be calculate automaticaly when item price change

    I need the sum of 3 fields id="total_item_1" id="total_item_2" id="total_item_3"
    and the grand total field have id="grandTotal"

    As I don't use quantity so what will be the js function?

    Thanks for your help
  • OK, I don't get it. I've literally copies the code from top of the page to set up a simple bare bones example. I can't get it to work. What am I missing?


    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitiona...;
    <html xmlns="http://www.w3.org/1999/xhtml">;
    <head>

    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Untitled Document</title>

    <script type="text/javascript" src="scripts/jquery-1.3.1.min.js"></script>

    <script type="text/javascript" src="scripts/jquery.calculation.min.js"></script>

    <script type="text/javascript">
        $(document).ready(function (){

            function recalc(){
                // run the calc() method on each of the "total" fields
                $("[@id^=total_item]").calc(
                    // the equation to use for the calculation
                    "qty * price",
                    // we now define the values for the variables defined in the equation above
                    {
                        // instead of using a static value, we use a jQuery object which grabs all the quantities
                        qty: $("input[@name^=qty_item_]"),
                        // now we define the jQuery object which reads in the "price" from the table cell
                        price: $("[@id^=price_item_]")
                    },
                    // this function is execute after the calculation is completed, which allows us to
                    // add formatting to our value
                    function (s){
                        // return the number as a dollar amount
                        return "$" + s.toFixed(2);
                    },
                    // once all calculations are completed, we execute the code below
                    function ($this){
                        // now we get the sum() of all the values we just calculated
                        var sum = $this.sum();

                        // now that we have the grand total, we must update the screen
                        $("#grandTotal").text(
                            // round the results to 2 digits
                            "$" + sum.toFixed(2)
                        );
                    }
                );
            }

            // bind the recalc function to the quantity fields
            $("input[@name^=qty_item_]").bind("keyup", recalc);
        });
    </script>
    </head>

    <body>
    <table width="500">
    <col style="width: 50px;" />
    <col />
    <col style="width: 60px;" />
    <col style="width: 110px;" />
    <tr>
      <th>
        Qty
      </th>
      <th align="left">
        Product
      </th>
      <th>
        Price
      </th>
      <th>
        Total
      </th>
    </tr>
    <tr>
      <td align="center">
        <input type="text" name="qty_item_1" id="qty_item_1" value="1" size="2" />
      </td>
      <td>
        <a href="http://www.packtpub.com/jQuery/book">Learn... jQuery</a>
      </td>
      <td align="center" id="price_item_1">
        $39.99
      </td>
      <td align="center" id="total_item_1">
        $39.99
      </td>
    </tr>
    <tr>
      <td align="center">
        <input type="text" name="qty_item_2" id="qty_item_2" value="1" size="2" />
      </td>
      <td>
        <a href="http://jquery.com/">jQuery Donation</a>
      </td>
      <td align="center" id="price_item_2">
        $14.99
      </td>
      <td align="center" id="total_item_2">
        $14.99
      </td>
    </tr>
    <tr>
      <td colspan="3" align="right">
        <strong>Grand Total:</strong>
      </td>
      <td align="center" id="grandTotal">
      </td>
    </tr>
    </table>
    </body>
    </html>
  • @Trey:

    Most likely you're not pointing to the correct location of the JS scripts.
  • Hi Dan,

    thank you for a great plugin, it fits my needs perfectly!

    I have a small problem with european number formatting. I have implemented the code from http://www.pengoworks.com/workshop/jquery/calculat... and it works for inputs (I can enter quantity 2,5 (two and a half) and it will be recognized as it should in the calculation. However, total result (I don't use Grand Total!) uses dots. For example:

    2 x 2,5 = 5.0

    How can I turn that dot in comma? Here is my code, if it helps:


    <code>
    <script type="text/javascript">
        var bIsFirebugReady = (!!window.console && !!window.console.log);

        $(document).ready(
            function (){
                // update the plug-in version
                $("#idPluginVersion").text($.Calculation.version);

    /*
    // test precision
    $("body").prepend("<div id='nn'></div>");
    $("#nn").calc(
        // the equation to use for the calculation
        "qty * price * consumption * 0.01",
        // define the variables used in the equation, these can be a jQuery object
        {
            qty: 23,
            consumption: 5,
            price: 1.4
        }
    );
    */

    $.Calculation.setDefaults({
        // a regular expression for detecting European-style formatted numbers
        reNumbers: /(-|-\$)?(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})?/g
        // define a procedure to convert the string number into an actual usable number
        , cleanseNumber: function (v){
            // cleanse the number one more time to remove extra data (like commas and dollar signs)
            // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
            return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
        }
    })

    /*
                $.Calculation.setDefaults({
                    onParseError: function(){
                        this.css("backgroundColor", "#cc0000")
                    }
                    , onParseClear: function (){
                        this.css("backgroundColor", "");
                    }
                });
    */

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

                // automatically update the "#totalSum" field every time
                // the values are changes via the keyup event
                $("input[name^=sum]"),sum("keyup", "#totalSum");
            }
        );

        function recalc(){
            $("[id^=total_item]").calc(
                // the equation to use for the calculation
                "qty * price * consumption * 0.01",
                // define the variables used in the equation, these can be a jQuery object
                {
                    qty: $("[id^=qty_item_]"),
                    consumption: $("[id^=consumption_item_]"),
                    price: $("[id^=price_item_]")
                },
                // 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();

                    $("#grandTotal").text(
                        // round the results to 2 digits
                        "$" + sum.toFixed(2)
                    );
                }
            );
        }
        </script>

    <form onsubmit="return false;" id="frmCreateCheckboxRange" method="post" action="">
        <fieldset>
            <div id="formContent">

                <table width="560">
                    <col style="width: 100px;">
                    <col style="width: 100px;">
                    <col style="width: 360px;">
                    <tbody><tr>
                        <td align="center">
                            C
                        </td>
                        <td align="center">
                            P
                        </td>
                        <td align="center">
                            T
                        </td>
                    </tr>
                    <tr>
                        <td align="center">
                            <input type="text" size="3" value="5" id="consumption_item_1">
                        <td align="center">
                            <input type="text" size="3" value="10" id="price_item_1">
                        </td>
                        <td align="center" id="total_item_1"></td>
                    </tr>
                    <tr>
                </tbody></table>
            </div>
        </fieldset>
    </form>
    </code>
  • @Mims:

    You need to use the formatting callback to change the format. The issue is that the calc() returns a JS number, so to format the number to a locality you'll have to define the formatting callback to handle change the JS number into a format matching your locality.
  • Dan,

    thank you for your quick reply! I'm java newbie and I would be very grateful if you could explain how to "format callback to change the format".

    Probably something has to be changed in this part? :


    // 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();
  • @Mims:

    Yes, you need to change:

      // 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);
      },

    You're going to need to change the variable "s" to match the formatting you want (i.e. swap the periods and commas.) You can do that using the replace() method like what's in the cleanseNumber handler.
  • @Dan

    I copied that cleanseNumber part and changed "function(v)" to "function(s)", but it didn't help. Some changes didn't help either. Here's my current code, probably I don't know where and what to paste:


    // 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);
    },

    , cleanseNumber: function (s){
       // use this for European numbers: s.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
       return s.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
    }


    Thank you for your help!
  • Hi Dan, first of all, your plugin is really user-friendly and great!

    However, I'm new to jquery.

    I'm able to put an INPUT FIELD for Qty and the Price but at the Grand Total, I put a DISCOUNT INPUT FIELD. It will just subtract the value of Discount Field from the value of Grand Total.

    Can you pls. show me a code how to do that? I'm really just learning.

    Thanks and More power to your plugin! :)
  • Oh by the way, I read ALL the comments and no one asked the same question as mine, if there was, I might have missed it, that's why I hope you could help. Have a nice day.
  • Hi I have 2 divs that perform different calculation. But the calculation just only work on the last div. . . Here's my code. . .

        <script type="text/javascript" src="js/jquery.field.js"></script>
        <script type="text/javascript" src="js/jquery.calculation.js"></script>
        <script type="text/javascript">
        var bIsFirebugReady = (!!window.console && !!window.console.log);

        $(document).ready(function (){
                // update the plug-in version
                $("#idPluginVersion").text($.Calculation.version);


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

                recalc();


            }
        );

        function recalc(){
            $("[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: $("[id^=price_item_]")
                },
                // define the formatting callback, the results of the calculation are passed to this function
                function (s){
                    // return the number as a dollar amount
                    return "Php " + 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();

                    $("#grandTotal").text(
                        // round the results to 2 digits
                        "Php " + sum.toFixed(2)
                    );
                }
            );
        }



        </script>

          <script type="text/javascript">
        var bIsFirebugReady = (!!window.console && !!window.console.log);

        $(document).ready(function (){
                // update the plug-in version
                $("#idPluginVersion").text($.Calculation.version);


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

                //recalc();

          $("input[name^=aqty_item_]").bind("keyup", recalc2);
          recalc2();
            }
        );

        function recalc2(){
            $("[id^=atotal_item]").calc(
                // the equation to use for the calculation
                "aqty * aprice",
                // define the variables used in the equation, these can be a jQuery object
                {
                    aqty: $("input[name^=aqty_item_]"),
                    aprice: $("[id^=aprice_item_]")
                },
                // define the formatting callback, the results of the calculation are passed to this function
                function (t){
                    // return the number as a dollar amount
                    return "Php " + t.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 asum = $this.sum();

                    $("#agrandTotal").text(
                        // round the results to 2 digits
                        "Php " + asum.toFixed(2)
                    );
                }
            );
        }

        </script>



              <table width="100%" border="0" cellspacing="0" cellpadding="0" class="services-table">
                   <tr>
                    <td width="60"> </td>
                    <td><h3 style="margin: 0;">Quantity</h3></td>
                    <td><h3 style="margin: 0;">Description</h3></td>
                    <td > </td>
                    <td><h3 style="margin: 0;">Prices in Php</h3></td>
                    <td style="padding-bottom: 10px;"> </td>
                   </tr>


                   <tr>
                    <td width="60"> </td>
                    <td width="13%"><input name="aqty_item_1" id="aqty_item_1" type="text" size="4" /></td>
                    <td width="50%"></td>
                    <td width="5"> </td><input type="hidden" name="aprice_item_1" id="aprice_item_1" value="250.00" />
                    <td><span class="race-num" id="atotal_item_1"></span></td>
                    <td width="50"> </td>
                   </tr>

                   <tr>
                    <td width="60"> </td>
                    <td width="13%"><input name="aqty_item_2" id="aqty_item_2" type="text" size="4" /></td>
                    <td width="50%">3.5 m x 10 m dd </td>
                    <td width="5"> </td><input type="hidden" name="aprice_item_2" id="aprice_item_2" value="15000.00" />
                    <td><span class="race-num" id="atotal_item_2"></span></td>
                    <td width="50"> </td>
                   </tr>



                   <tr>
                    <td> </td>
                    <td colspan="4" class="total" id="agrandTotal">TOTAL: </td>
                    <td> </td>
                   </tr>

                  </table>
                  <br />
                </div>


                  <table width="100%" border="0" cellspacing="0" cellpadding="0" class="services-table">
                   <tr>
                    <td width="60"> </td>
                    <td><h3 style="margin: 0;">Quantity</h3></td>
                    <td><h3 style="margin: 0;">Description</h3></td>
                    <td > </td>
                    <td><h3 style="margin: 0;">Prices in Php</h3></td>
                    <td style="padding-bottom: 10px;"> </td>
                   </tr>


                   <tr>
                    <td width="60"> </td>
                    <td width="13%">
                      <input name="qty_item_1" id="qty_item_1" type="text" size="4" />

                    </td>
                    <td width="50%">sdadf</td>
                    <td width="5"> </td><input type="hidden" id="price_item_1" id="price_item_1" value="1000.00" />
                    <td><span class="race-num" id="total_item_1"></span></td>
                    <td width="50"> </td>
                   </tr>

                   <tr>
                    <td width="60"> </td>
                    <td width="13%"><input name="qty_item_2" id="qty_item_2" type="text" size="4" /></td>
                    <td width="50%">safaf</td>
                    <td width="5"> </td><input type="hidden" id="price_item_2" id="price_item_2" value="75000.00" />
                    <td><span class="race-num" id="total_item_2"></span></td>
                    <td width="50"> </td>
                   </tr>

                   <tr>
                    <td width="60"> </td>
                    <td width="13%"><input name="qty_item_3" id="qty_item_3" type="text" size="4" /></td>
                    <td width="50%">sfa</td>
                    <td width="5"> </td><input type="hidden" id="price_item_3" id="price_item_3" value="150000.00" />
                    <td><span class="race-num" id="total_item_3"></span></td>
                    <td width="50"> </td>
                   </tr>




                   <tr>
                    <td> </td>
                    <td colspan="4" class="separator"> </td>
                    <td> </td>
                   </tr>

                   <tr>
                    <td> </td>
                    <td colspan="4" class="total">TOTAL: <font id="grandTotal"></font></td>
                    <td> </td>
                   </tr>

                  </table>
                  <br />

    That's the problem I have recalc2 doesn't work. .. But I tried extracting it and have it tested it via a remote file. So it seems the problem has something to do with multiple calculations I guess. . .
  • @Cha:

    I think you must have a problem somewhere else in your code, because when I cut and paste that example into a new HTML file it works for me.
  • Yeah, you're probably right. Cos I got a lot of jQuery scripts on my testing file. . . I have noticed that actually already. Anyways, thanks Sir Dan awesome plugin. I'm subscribing to your posts from now on. . . XD

    Thanks,

    Cha
  • Hello there!

    I love the script so far, however I am running into an issue in getting it to work correctly. I imagine I'm doing something greatly wrong, but I can't figure it out.

    I've got 4 fields. 1 is a checkbox that is mandatory, then 2 quantity fields with different prices, and then another checkbox that adds a certain amount.

    I'm running both your script and the field plugin.

          <script type="text/javascript">
                $(document).ready(
                    function recalc(){
            $("[id^=fees]").calc(
                // the equation to use for the calculation
                "firstregistrant + (additionalregistrants * 200) + parkingpermit + (additionalnotebooks * 50)",
                // define the variables used in the equation, these can be a jQuery object
                {
                    firstregistrant: $("[name^=firstregistrant]"),
                    additionalregistrants: $("[name^=additionalregistrants]"),
                    additionalnotebooks: $("[name^=additionalnotebooks]"),
                    parkingpermit: $("[name^=parkingpermit]")
                },
                // 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();

                    $("#grandTotal").text(
                        // round the results to 2 digits
                        "$" + sum.toFixed(2)
                    );
                }
            );
        }
        )

        </script>

    and here is the form (sorry it's really dirty, it's in an ASP write.)

    <tr bgcolor=""#FFFFFF""><td colspan=""3"">Fees:</td></tr><tr bgcolor=""#CCCCCC""><td height=""27"" align=""right"">First/Only registrant - $400</td><td colspan=""2"" class=""leftalign""><input type=""checkbox"" name=""firstregistrant"" id=""firstregistrant"" checked=""checked"" value=""400""></td></tr><tr bgcolor=""#FFFFFF""><td height=""27"" align=""right"">Additional Registrants - $200 each</td><td colspan=""2"" class=""leftalign""><label><input type=""text"" name=""additionalregistrants"" id=""additionalregistrants"" placeholder=""0"" size=""3"" maxlength=""2""></label></td></tr><tr bgcolor=""#CCCCCC""><td height=""27"" align=""right"">Parking Permit for Marstellar Garage - $15</td><td colspan=""2"" class=""leftalign""><input type=""checkbox"" name=""parkingpermit"" id=""parkingpermit"" value=""15""></td></tr><tr bgcolor=""#FFFFFF""><td height=""27"" align=""right"">Additional Workshop Notebooks - $50 each</td><td colspan=""2"" class=""leftalign""><label><input type=""text"" name=""additionalnotebooks"" id=""additionalnotebooks"" placeholder=""0"" size=""3"" maxlength=""2""></label></td></tr><tr bgcolor=""#CCCCCC""><td height=""27"" align=""right"">Total Due</td><td colspan=""2"" class=""leftalign"" class=""grandTotal"" id=""fees""></td></tr>

    Any help would be greatly appreciated
  • @Caleb:

    Before I can help, I need to know:

    1. What you're trying to accomplish
    2. What results you're expecting
    3. What results you're actually currently seeing
  • I would like to add the items together when checked or a number inputted, the checkbox for $400, the checkbox for $15, and the 2 number boxes (inputted number*$200 and inputted number*$50)

    So when they check a box or whatnot it should update the Total Due price. Currently it doesn't seem to live update. It will start at $400 as that box is pre-selected. If I select some boxes and then submit and THEN hit back it will have the updated price.

    You can check it out here: https://www.agecon.purdue.edu/commercialag/registr...

    In the end I would like to have the final number able to be submitted along with the information in that form.

    Thanks!
  • @Caleb:

    The problem is you're only running the recalc() which the page first loads--you have bound any events to the page to update those fields. You're going to need to bind events to run the recalc() when the fields are updated. For the checkboxes, you can bind a click event to trigger the recalc() function. For the text boxes, you'll want to bind a keyup event.
  • I could really do with some help please.

    Is there a way of using a radio button for Category A and B so you only have the option of selecting one category or another. Secondly once you select a category I just need it to display only one price rather than two as in the example below.

    Hope this all makes sense?

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>jQuery Calculation Plug-in</title>

        <!---// load jQuery v1.3.1 from the GoogleAPIs CDN //--->
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/...;

        <!--// load jQuery Plug-ins //-->
     <script type="text/javascript" src="jquery.field.js"></script>
      <script type="text/javascript" src="jquery.calculation.js"></script>
      <script type="text/javascript">
      var bIsFirebugReady = (!!window.console && !!window.console.log);

      $(document).ready(function (){
         // update the plug-in version
         $("#idPluginVersion").text($.Calculation.version);


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

         recalc();


       }
      );

      function recalc(){
       $("[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: $("[id^=price_item_]")
         },
         // 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();

          $("#grandTotal").text(
            // round the results to 2 digits
            "£" + sum.toFixed(2)
          );
         }
       );
      }



      </script>

      <script type="text/javascript">
      var bIsFirebugReady = (!!window.console && !!window.console.log);

      $(document).ready(function (){
         // update the plug-in version
         $("#idPluginVersion").text($.Calculation.version);


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

         //recalc();

    $("input[name^=aqty_item_]").bind("keyup", recalc2);
    recalc2();
       }
      );

      function recalc2(){
       $("[id^=atotal_item]").calc(
         // the equation to use for the calculation
         "aqty * aprice",
         // define the variables used in the equation, these can be a jQuery object
         {
          aqty: $("input[name^=aqty_item_]"),
          aprice: $("[id^=aprice_item_]")
         },
         // define the formatting callback, the results of the calculation are passed to this function
         function (t){
          // return the number as a dollar amount
          return "£" + t.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 asum = $this.sum();

          $("#agrandTotal").text(
            // round the results to 2 digits
            "£" + asum.toFixed(2)
          );
         }
       );
      }

      </script>


    </head>
    <body>




    <table width="800" border="0" cellspacing="0" cellpadding="0" class="services-table">
    <tr>
    <td width="60"> </td>
    <td><h3 style="margin: 0;">Activities</h3></td>
    <td><h3 style="margin: 0;">CATEGORY A</h3></td>
    <td><h3 style="margin: 0;">CATEGORY B</h3></td>
    <td > </td>
    <td><h3 style="margin: 0;">Price</h3></td>
    <td style="padding-bottom: 10px;"> </td>
    </tr>


    <tr>
    <td width="60"></td>
    <td width="13%">Activity 1</td>
    <td width="50%"><input name="aqty_item_1" id="aqty_item_1" type="text" size"2" /></td>
    <td width="50%"><input name="aqty_item_2" id="aqty_item_2" type="text" size="2" /></td>
    <td width="5"><input type="hidden" name="aprice_item_1" id="aprice_item_1" value="154.00" /><input type="hidden" name="aprice_item_2" id="aprice_item_2" value="175.00" /></td>
    <td><span class="race-num" id="atotal_item_1"></span></td>
    <td width="50"> </td>
    </tr>

    <tr>
    <td width="60"></td>
    <td width="13%"></td>
    <td width="50%">&nbsp;</td>
    <td width="50%">&nbsp;</td>
    <td width="5"></td>
    <td><span class="race-num" id="atotal_item_2"></span></td>
    <td width="50"> </td>
    </tr>
    <tr>
     <td></td>
     <td>&nbsp;</td>
     <td>&nbsp;</td>
     <td>&nbsp;</td>
     <td></td>
     <td>&nbsp;</td>
     <td></td>
    </tr>



    <tr>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td>TOTAL: <font id="agrandTotal"></font></td>
    <td></td>
    </tr>
    </table>
    <br />
    </div>


    </body>
    </html>
  • Hi - great plug-in. What do I need to change to display commas to split the thousands i.e. £1,000,000.00?
  • Hi,

    I use this plugin to summarize ordinary input fields, radio buttons and a select list. I have bound my calc to both keyup and change, but I can not get the value from the select list.
    I use the name structure to grab all the fields like this:

    $("input[name$='[amount]']").sum({


    Is there something special one needs to do in order to support select lists ?
  • @Soren:

    The only thing about a select element that might cause you problem is if you're using a multi select and select multiple values. That might get you unexpected results.

    Are you using the Field Plug-in? What's your code look like?
  • The min version of field plug-in is loaded before the calculation plugin - also min version.

    My code looks like this:

    <script type="text/javascript">
    $(document).ready(
     function (){
      $("input[name$='[amount]']").sum({
      bind: "change",
      selector: "#js_sum_amount",
      onParseError: function(){
       this.css("backgroundColor", "#cc0000")
      },
      onParseClear: function (){
       this.css("backgroundColor", "");
      },
      oncalc: function (value, settings){
       // you can use this callback to format values
       // Use .val for input methods
       // Use .html for html methods
       $(settings.selector).html("$" + value.toFixed(2));
      }
      });
    });
    </script>

    The actual segment of the page that contains the Select list is:
    <li class="select optional" id="items_223__amount_input">
    <label for="items_223__amount">Membership(s)</label>
    <select id="items_223__amount" name="[items[223]][amount]" style="font-size: 2em; width: 50%;">
    <option value=""></option>
    <option value="0">No Membership</option>
    <option value="10">1 Member $10</option>
    <option value="18">2 Members $18</option>
    <option value="23">3 Members $23</option>
    <option value="28">4 Members $28</option>
    </select></li>

    Is there a recommended way to bind to multiple events ? Obviously you can copy the calc block and bind to a different element, but that as non-DRY as it gets.
  • Hi great plugin. My problem is this:

    I have select option boxes all with incremental option fields as such below (just example mocked up)
    <tr><td>
    Qty 1 input $("#qty_")</td>
    <td>
    <select id="1">
    <option id="apples_1" value="3">3</option>
    <option id="bananas_1" value="2">2</option>
    </select>
    <input type="hidden" id="total_1" value="">
    </td></tr>
    <tr><td>
    Qty 2 input $("#qty_")</td>
    <td>
    <select id="2">
    <option id="apples_2" value="5">5</option>
    <option id="bananas_2" value="2">2</option>
    </select>
    <input type="hidden" id="total_2" value="">
    </td></tr>
    <td>
    <input type="text" id="grandTotal" value="">
    </td>

    I have it all working fine and dandy but my problem comes with changing the actual values of the select options on recalc. Basically I want the hidden field to parse the number in the respective select box to dynamically change the value. If I simply use a $("apples_"), all the apple values will sum. Assuming I need to put in array for elements like foreach $("apples_")[i]????

    Any help very appreciated, this is driving me mad!!!
  • @CT:

    You don't need ids on your <option /> tags. What you need is to id's on your select tag (like id="fruit_X", instead of just id="X") to match your "total_X" lines.
  • Thanks for your prompt response!! I am posting my actual code to ensure that we are on the same page.

    plugin code

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


    function fruittotal(){
      $("[id^=total_fruit]").calc(
          "qty * fruit",
          // define the variables used in the equation, these can be a jQuery object
          {
            qty: $("input[name^=qty_item_]"),
            fruit: $("option[id^=fruit_item_]")
          },
             // 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){
                    var sum = $this.sum();
                    $("#fruitTotal").text(
                        // round the results to 2 digits
                        sum.toFixed(2)
                    );
                }
            );
        }


    HTML

            <div id="formContent">

                <table width="500">
                    <col style="width: 50px;">
                    <col>
                    <col style="width: 60px;">
                    <col style="width: 110px;">
                    <tbody><tr>
                        <th>
                            Qty
                        </th>

                        <th>
                          TOTal
                        </th>
                    </tr>
                    <tr>
                        <td align="center">
                            <input name="qty_item_1" id="qty_item_1" value="1" size="2" type="text">
                        </td>
                        <td>
                    <select>
    <option name="fruit_item_1" id="fruit_item_1" value="59">59 fruits</option>
    </select>
    </td>

                        <td><input type="hidden" id="total_fruit_1" value=""></td>
                    </tr>
                    <tr>
                        <td align="center">
                            <input name="qty_item_2" id="qty_item_2" value="2" size="2" type="text">
                        </td>
                        <td>
                    <select>
    <option name="fruit_item_2" id="fruit_item_2" value="288">288 fruits</option>
    </select>
    </td>
                        <td><input type="hidden" id="total_fruit_2" value=""></td>
                    </tr>
                    <tr>
                    <td align="center">
                            <input name="qty_item_3" id="qty_item_3" value="2" size="2" type="text">
                        </td>
                        <td>
                    <select>
    <option name="fruit_item_3" id="fruit_item_3" value="509">509 fruits</option>
    </select>
    </td>

    <td><input type="hidden" id="total_fruit_3" value=""></td>
                    </tr>
                    <tr>
                        <td colspan="3" align="right">
                            <strong>Total:</strong>
                        </td>
                        <td id="fruitTotal" align="center"></td>
                    </tr>
                </tbody></table>
            </div>
        </fieldset>
    </form>


    So I am clear, if I change the qty_2 value, it will update the fruitTotal and also update the fruit_item_2 value to the fruit_total_2 val? This done by just calling selector on select vs option? Thanks again. CT
  • @CT:

    You want the name attribute on your <select /> tags, not your <option /> tags as I stated in my last post. Your selector for fruit should look like this:

    $("select[id^=fruit_item_]")

    And your HTML should look like:

    <select name="fruit_item_3" id="fruit_item_3">
    <option value="509">509 fruits</option>
    </select>

    You will also want to use my Field Plug-in to make sure the values from the <select /> elements are correctly processed.
  • Hi Dan:

    Thanks for a great plugin. Question: I'm encountering a strange bug in Chrome v12. In a form with n elements I want to .sum(), if the total value exceeds the maxlength attribute set on the #total field, an error is displayed (saying the maxlength has been surpassed), and the form submission is stopped (buttons seem disabled) Very weird. Any thoughts?
  • @Joe:

    Haven't heard of that problem before, but I can't believe there's anything in the Calc plug-in that's causing the problem. I'd imagine if you tried updating the form value via straight JS, you'd see the same behavior.

    Why not just make the #total element a div or a span element?

    I don't suggest trusting "total" values calculate in the user's browser anyway (since it's so easy for a client to send inaccurate data) and always recommend for trusted calculations that all real logic is done on the server-side anyway.

    Lastly, you can just bump up the maxlength of the field. You shouldn't be using this as a real constraint mechanism anyway, so it's mainly a UI convenience convention.
  • Thanks Dan for the quick response. I thought about it more last night and came to the same conclusion - that it is not the plugin. The idea of making the #total field a div is a very good one and will probably be the end solution.

    Testing using straight JS is a good idea too and i will do that. Thanks again for the quick reply, good advice, and good plugin!
  • Could anybody tell me on how to implement subtraction like with calc function.
  • Hi Dan,

    Thanx for the script. I've got it working fine, but I can't change to european formating. I don't know where I must put the following code. Can you tell me where and how I must do that? Thanks :)

    $.Calculation.setDefaults({
        // a regular expression for detecting European-style formatted numbers
        reNumbers: /(-|-\$)?(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})?/g
        // define a procedure to convert the string number into an actual usable number
        , cleanseNumber: function (v){
            // cleanse the number one more time to remove extra data (like commas and dollar signs)
            // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
            return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
        }
    })

    I've this in serveral places but I can't make it work :(

    Can you help me please?
  • @VDEKKERNL:

    See my response to when you asked this question yesterday on a different blog entry:

    http://blog.pengoworks.com/index.cfm/2008/2/20/Wat...
  • European-style formating don't work in Firefox 7
  • @pmatulka: Do you know a bugfix for this problem?
  • Code:

    <script type="text/javascript">
    $.Calculation.setDefaults({
        // a regular expression for detecting European-style formatted numbers
        reNumbers: /(-|-\$)?(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})?/g
        // define a procedure to convert the string number into an actual usable number
        , cleanseNumber: function (v){
            // cleanse the number one more time to remove extra data (like commas and dollar signs)
            // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
            return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
        }
    })

    $(document).ready(function ()
    {
    $("input[name^='nt']").sum("keyup", "#total_nt");
    $("input[name^='ot']").sum("keyup", "#total_ot");
    }
    );

    </script>

    <table>
    <tr>
    <td>NT1: <input type="text" name="nt[1]" value="1,1"></td>
    <td>OT1: <input type="text" name="ot[1]" value="1,2"></td>
    </tr>
    <tr>
    <td>NT2: <input type="text" name="nt[2]" value="1,3"></td>
    <td>OT2: <input type="text" name="ot[2]" value="1,4"></td>
    </tr>
    <tr>
    <td>SUM_NT: <input type="text" id="total_nt" name="total_nt"></td>
    <td>SUM_OT: <input type="text" id="total_ot" name="total_ot"></td>
    </tr>
    </table>

    Results in: IE 6 - 9, Firefox 3.6 - 6, Chrome 12, Opera 11
    NT1: 1,1
    OT1: 1,2
    NT2: 1,3
    OT2: 1,4
    SUM_NT: 2.4
    SUM_OT: 2.6

    All browser show dots in sum. Nothing help.

    Results in: Firefox 7
    NT1: 1,1
    OT1: 1,2
    NT2: 1,3
    OT2: 1,4
    SUM_NT: 4
    SUM_OT: 6

    Firefox 7 sum only last number.
  • @pmatulka:

    If you change the regex to the following, it should start working again for you:

    (-?\$?)(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})
  • @Dan

    Did not help. Results is this same:

    IE 6 - 9, Firefox 3.6 - 6, Chrome 12, Opera 11:
    NT1: 1,1
    OT1: 1,2
    NT2: 1,3
    OT2: 1,4
    SUM_NT: 2.4
    SUM_OT: 2.6

    All browser show dots in sum. Nothing help.

    Firefox 7:
    NT1: 1,1
    OT1: 1,2
    NT2: 1,3
    OT2: 1,4
    SUM_NT: 4
    SUM_OT: 6

    Firefox 7 sum only last number.
  • @pmatulka:

    Make sure to check out this working example:
    http://jsfiddle.net/dswitzer/drv7v/1/

    This example works fine for me in FF7. You may have an issue somewhere else in your code. Of course, make sure you have the most recent version of the library.
  • @Dan
    Thanks. It's working! But sum shows dot not comma.

    Below whole "test.php" code:

    <html>
    <head>
    <title>test</title>
    <script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>
    <script type="text/javascript" src="js/jquery.calculation.min.js"></script>
    </head>

    <body>
    <script type="text/javascript">
    $.Calculation.setDefaults({
      // a regular expression for detecting European-style formatted numbers
      reNumbers: /(-?\$?)(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})/g
      // define a procedure to convert the string number into an actual usable number
      , cleanseNumber: function (v){
        // cleanse the number one more time to remove extra data (like commas and dollar signs)
        // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
        return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
      }
    });

    $(document).ready(function ()
    {
    $("input[name^='nt']").sum("keyup", "#total_nt");
    $("input[name^='ot']").sum("keyup", "#total_ot");
    }
    );

    </script>

    <table>
    <tr>
    <td>NT1: <input type="text" name="nt[1]" value="1,1"></td>
    <td>OT1: <input type="text" name="ot[1]" value="1,2"></td>
    </tr>
    <tr>
    <td>NT2: <input type="text" name="nt[2]" value="1,3"></td>
    <td>OT2: <input type="text" name="ot[2]" value="1,4"></td>
    </tr>
    <tr>
    <td>SUM_NT: <input type="text" id="total_nt" name="total_nt"></td>
    <td>SUM_OT: <input type="text" id="total_ot" name="total_ot"></td>
    </tr>
    </table>
    </body>
    </html>

    Results in: IE 6 - 9, Firefox 3.6 - 7, Chrome 12, Opera 11
    NT1: 1,1
    OT1: 1,2
    NT2: 1,3
    OT2: 1,4
    SUM_NT: 2.4
    SUM_OT: 2.6

    Could you check what should be done to the result was as follows (in sum comma not dot):
    NT1: 1,1
    OT1: 1,2
    NT2: 1,3
    OT2: 1,4
    SUM_NT: 2,4
    SUM_OT: 2,6
  • @pmatulka:

    That's by design. The plug-in deals with JavaScript numbers--which use a period for the decimal place.

    The entire purpose of the reNumbers and cleanseNumber defaults are just to clean a formatted number into something JavaScript can understand as a number.

    So, in your case 1,1 is converted to 1.1 so JavaScript can actual treat it like a number. If you want to apply formatting to the number, you will have to use the oncalc callback. Here's an example from the docs:

    $("input[name^='avg']").avg({
         bind: "keyup"
        , selector: "#totalAvg"
        , oncalc: function (value, settings){
            // you can use this callback to format values
            $(settings.selector).html("$" + value);
        }
    });

    The above example just adds a "$" to the output. You're going to want to replace that with something that formats your number like you want.

    Eventually I plan on re-writing this from scratch and add better support for formatting numbers and potentially handling European-style formatting in a more elegant manor.
  • Hi, thanks for the great script. Quick question: How do you sum to 4 digits?
    i.e, in your sums calculation example, unless there is a remainder it sums to 2 digits.. 20.00 + 20.00 = 40, what i need is 20.00 + 200 = 40.00


    Thanks..

    Ray
  • Meant 20.00 + 20.00 = 40.00
  • @Ray:

    The Calculation example linked to in this blog entry works fine with whole numbers, so look at for examples. The trick is if you need your value to always show in a certain format, then you must use a callback to format the calculated number to the number mask you need.
  • Hey Dan ... I added your plug-in into a php script with a MySQL table without problem, but as I never worked before 2 update a jquery script and I need 2 add a couple fields, I would like 2 count with a short help 2 understand what I need 2 do.

    I am working in a invoice model page and I would like 2 know how 2 add a 12 % field from the #grandTotal and later make a finish total that come from 12% plus the #grandTotal, 2 get something like:
    Subtotal: 100.00
    12%:    12.00
    Total:   112.00
  • Hi Dan,

    Not sure if this has been asked before, but I need the price of my items to change as the quantity increases. For instance: if qty = 1, then price = 30.00, but if qty > 1, then price = 20.00

    As my jQuery knowledge is very basic (and I mean very), I was wondering if you could help me to implement this.

    Thanks so much!

    Laura
  • @laura:
    I guess that you can use something like that. I need 2 check more 2 know if can work without any problem but basically should have this structure.

    if(qty > 1) {
        var price = 20.00;
      } else {
        var price = 30.00;
       }
  • I found the clue 2 make the issues that I was needed just adding some variables and basic math operations into the recalc function and of course adding some rows and cells in the table used to show the values. Quick and easy. Just I need 2 learn how 2 used a standard format number and done deal

    // 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();

                    $("#grandTotal").text(
                        // round the results to 2 digits
                         sum.toFixed(2)

                    );

                    // update the total
                    var impuestoiva = $('#MontoIva').val();
                    var sub_total  = $('#grandTotal').sum();
                    var total_iva  = (sub_total * impuestoiva) / 100;
                    var total    = sub_total + total_iva;
                    $("#totalIva").text(
                        // round the results to 2 digits
                         total_iva.toFixed(2)

                    );

                    $("#totalGeneral").text(
                        // round the results to 2 digits
                         total.toFixed(2)

                    );

                }
  • Hi

    I keep getting this error:
    TypeError: _._ is undefined

    And I can't seem to work out why

    the fields are:
    adults1 * atotal1 + juniors1 * jtotal1 = subtotal1
    adults2 * atotal2 + juniors2 * jtotal2 = subtotal2

    the subtotals then add up at the bottom into a total field

    Any help would be great

    thanks
  • Hi Dan

    I've been using your excellent plugin for a few years now and have never had a problem until now. My code works perfectly on IE and Chrome, but it doesn't work on Firefox 9. I think it may have something to do with parsing text in European number format, i.e. when a comma is used instead of a decimal point.

    You can see the code in action here: http://www.parquewarner.com/es/solicitud-de-reserv.... The price of tickets is calculated correctly in Chrome and IE, and it used to work in Firefox, but since I upgraded to FF9 it has stopped working.

    If you could spare a few minutes to look at the problem I'd be very grateful.

    Thank you
    Miriam
  • Miriam:

    Are you using v0.4.09? There were some fixes to the regex for FF in the latest revision.

    Also, make sure you using the correct default settings:

    $.Calculation.setDefaults({
        // a regular expression for detecting European-style formatted numbers
        reNumbers: /(-?\$?)(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})/g
        // define a procedure to convert the string number into an actual usable number
        , cleanseNumber: function (v){
            // cleanse the number one more time to remove extra data (like commas and dollar signs)
            // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
            return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
        }
    })

    The recommend RegEx has definitely changed in the past few years.
  • Thank you! It was the default setting for detecting European numbers that caused the problem. I used your suggested setting and it works again. Wonderful!

    Thank you for your help, and for the great plugin. It has saved me countless hours.

    Miriam
  • Hi Dan,

    Thanks for the plugin - works great, but I do have a problem w/ it working in FF - at least the last two versions of FF do not display the sum() result. I am using the latest version (v0.4.09) of the plugin.

    If you want to have a look, the front end is at http://www.drgily.com/test.php

    You will have to enter a food or two and you will see tables for each meal showing up. At the end, I have another small table that is totaling all the sums in previous tables, and I use the following code to generate the sum:

          totals = ( $(".subtotals").sum() );
          $("#total_cals").html(totals);

    where "subtotals" is the cell class of individual meal tables and "total_cals" is the id of the final table where I display the grand-total.

    It works fine in IE, Chrome, Safari, etc., but not in FF.

    Any ideas or suggestions would be greatly appreciated!

    Gily
  • I use jquery calculation plugin here. I have a problem with function recalc. I would like that variables qty and price would be float. I know that I have to use parseFloat(), but if I make for example:

    qty: $(parseFloat("input[name^=qty_item_]"))

    or

    qty: parseFloat($("input[name^=qty_item_]"))

    This doesn't work.

    Does somebody have any ideas?

    function recalc(){
        $("[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: $("[id^=price_item_]")
          },
          // 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();

            $("#grandTotal").text(
              // round the results to 2 digits
              sum.toFixed(2)+" z?"
            );
          }
        );
      }

    If I multiply 2 X 2.2 I get 4.0. Should be 4.4
  • Previous issue has been resolved. I wasn't used $.Calculation.setDefaults .
  • Hi Dan,

    Thanks so much for the amazing plug-in. I've only been using it for a few days now, and its been amazing so far.

    I have a question in regards to this page:
    http://thefutureforward.com/play/calculations/

    So far things are working well, but I'd like to add a bit more functionality. The idea here is a basic carbon footprint calculator, where you can specify the amount of homes/vehicles you own and then generate the amount of carbon tons that is producing (right now, it's just a bunch of arbitrary numbers).

    The issue with my setup so far is that some folks may have multiple homes of different types (perhaps 1 apartment, 2 condos, etc.) Right now, it only allows you to select one type of home and add it..when you select a different type from the <select>, it changes the number (instead of adding them all together).

    I'm sure there's an extra step here that I'm missing (perhaps building an array of values each time you click "ADD" for each select...) but I'm just not sure how to do it. Hopefully there's a different way of building this function that'll get the job done.

    I would appreciate any and all thoughts that you have! Thanks so much.
  • @Nick:

    Instead of having a fixed asset type for each row, you'll want the user to be able to add any type of asset and add as many as they like. While you certainly can use my plug-in to do the calcs, I think a better UI would have an pool of assets the user can choose from and then selecting an asset shows them under a selected resources list--with the total footprint listed under all the selected options.

    In essence the problem isn't really a problem with the Calculation plug-in, but a design change you'd need to do.
  • Hey Dan,

    I agree with your assessment. Unfortunately, the creative team of the client I'm working with is providing the design/layout of the form, so I have no say in the matter, and this is what they've come up with. Argh.

    Here's my really ugly (but generally working) stab at it:

    http://thefutureforward.com/play/calculations/inde...

    Would love to hear any thoughts you might have on how to clean this up!

    Thanks again.
  • Forgot to mention that the "current total" and "total" columns are just for testing and aren't a part of the design.
  • Since I'm not showing the totals on screen (other than the "grand total"), I was able to simplify this greatly:

    http://thefutureforward.com/play/calculations/
  • @Nick:

    First off, your original question to me was on how to fix the issue of people possibly having "multiple homes of different types." With the current design your creative people supplied, you're not going to be able to address it.

    That's why I suggested you change things so users could pick from a complete pool of assets and add as many as they need of each type. This fixes the original problem.

    As for what you currently have, what I'd do is add "input" and "change" events to your text and select elements which would fire off the calculation. That would allow you to get rid of the "Add" functionality altogether.

    Also, for the "subtotal_tons_" elements, why not just use a hidden form field? That seems better than trying to hide a table cell--it also reduces the HTML output.
  • Thanks for the tips, Dan. I agree that this could be laid out in a more usable fashion, but unfortunately I have no say. I also have to keep the "Add" functionality in place, as that is also a part of their design.

    I'll definitely go for the hidden form field for the "subtotal_tons_" elements. Good call.

    Thanks again for the tips and the amazing plugin!
  • One additional question Dan - right now, my code adds all of the items to the grand total if the "quantity" field has any number entered. Any tips on making it so that the only item that gets added is the one you click the "ADD" link for?
  • @Nick:

    First and foremost, I can't tell you how much I think you need to change the design requirements on this. The problems you keep bringing up are largely due to the design. I'd really try to go on bat and suggest to your design team a better way to handle it.

    Second, the calculation plug-in isn't designed to handle every situation. You'd probably be better off just coding a custom solution--as it's probably going to end up being more straightforward and intuitive in the long run.

    That said, you could probably solve you're problem by adding an additional hidden field who's value is either 0 or 1 and then multiplying your formula by this value. Clicking the "Add" link would change the value to "1". So you'd change your formula to something like:

    qty * select_option * do_add

    By default the do_add hidden field would be 0, so the result would always be zero. When the "Add" link is clicked, the value is changed to 1, thus keeping the original value.

    However, I think you're starting to hack the code a lot to get this to work and would be better off just hard coding a formula.
  • Thanks for the tip Dan! Much appreciated.
  • Hi Dan

    I love the plugin but am daunted when using it for a mobile website - if I change the input type to number to make life easier for a mobile user, the plugin doesn't work; if I keep the input type as text, all is well on an iPhone. Is there a simple fix I have overlooked?

    Thanks in advance
  • @John:

    Can you post an example that's not working?

    I'm guessing that changing the input's type attribute is breaking one of your jQuery selectors.
  • Hi Dan,
    I'm using the jquery.calculation plugin to sum form fields and it works as advertised, but I ran into an trouble when I started adding/removing fields to/from the form on the fly. I'm guessing I need to use jquery's delegate event handler for the adds, but not sure how to deal with the removed fields. Do you have any experience with such forms? I noticed on Feb 16 you suggested a similar approach to Nick, but didn't indicate how to deal with the new/removed form fields.
    Thx
  • @Blair:

    Yes, using a delegate will fix the issue of dynamically adding new fields. To handle a remove, all you need to do is manually trigger the event when you remove the field.

    So, taking the following example:

    $("input[@name^=qty_item_]").bind("keyup", recalc);

    You'd just need to do this on removal:

    $("input[@name^=qty_item_]").triggerHandler("keyup");

    All you're doing is manually triggering the event to run whenever you remove fields from the DOM so the calculation is re-run.
  • Hey Dan,

    great plugin you've got there!
    I got a little problem with my code. As the website is in the EU, I need to change the formatting to "xx,yy EUR".

    After I change the $.Calculation.setDefaults to EU-regex, the calculation with a comma works fine, but the result gets displayed with a point instead of comma... if you need to see the code, take a look at this paste: http://pastebin.com/yYGGQQLb

    As you can see, it's pretty like the tutorial. :) Hope you have a tip for me!
  • @Zedar:

    What you need to do is change the format callback to convert the number back to the format you want.

    The problem is the result of the calculation is always going to be a JavaScript number, so unless you reformat the value any decimal values will show with a period as the delimiter.

    To fix your issue, you need to find your ".toFixed(2)" lines and just apply some localized formatting to those values.

    See this example that uses a function for formatting the return value to European syntax:

    http://jsfiddle.net/dswitzer/drv7v/1/
  • Hey Dan,

    thank you very much! It works like a charm!!
  • Can you please look at http://216.81.97.174/default/includes/site_custom/...

    I can get the tabs to total but not get the totals to move to the totals tab.
  • http://216.81.97.174/default/includes/site_custom/...

    OK I go the totals and sub totals to work on the tabs and on the totals tabs.

    I just don't know how to get Totals at the bottom of the totals tab table.
  • Hello.
    I have a calculation with some items, that got different prices. Do I need to start a new function for every single price?
    There are 2 groups: Tickets; Merch. Every single Ticket and Merch-article has its own price. In the end I have 6x different tickets and 4 different merch articles+prices. You can see the code here: http://jsfiddle.net/wfGK2/
    (It's my first fiddle, i hope it works.)
    I stripped the code to a minimum. The problem is that "price: " just takes the first one it can find, as if [id^=price_item_] won't increase.

    Can you help me?
  • @Honse:

    Your code was basically correct (although it has way more markup than what's needed.) The only real problem was the price should have been mapped to the <span> tags directly. I just moved the id="price_item_" to the span tags and it's working now.

    See this working example:
    http://jsfiddle.net/wfGK2/1/
  • Hey Dan, great plug-in. Does exactly what I need.

    One issue though which may be due to how I have everything laid out. I am using your plug-in as a price updater. A person will input the daily price into a designated field and a table of prices will update according to the price they inputted. I have 3 input fields for different prices. So input A would update A prices, B for B prices and C for C prices.

    Each output (price_item_ & total_item_) are all named matched to the inputs (qty_item_). So that isn't the issue. The problem I am getting is that I enter a number into input A and everything updates according to input A. So B & C are updating with what I put in A, when they should update separately when a number is placed into B & C, respectively. So in the end, everything updates to A's input and B & C's inputs do nothing.

    Thanks.
  • @Myself

    Fixed it by making each input their own calc function.
  • @Sean:

    Glad you fixed the problem!
  • you can also check my simple implementation as a starter <a href="http://fundapass.blogspot.in/2012/10/excel-like-su... like jquery</a>
  • Hi,

    I'd like to use this plugin but with a litte modification.
    When we define the callback function :

    // define the finish callback, this runs after the calculation has been complete
       function ($this){ ... }

    I'd like to do a division instead of a sum(). How can I do that please ?

    I tried some things but I've got this error : TypeError: _._ is undefined.

    Thanks.
    Thomas.
  • @Thomas,

    There are no built-in support for product (multiplication) or division. I could add a product() method for multiplying numbers, but the order in division really matters. That's why there's method for subtraction either.

    For dividing, you'll need to build that logic manually.
  • Hello Dan,
    Great plug-in. My only problem is that I use a multi page form. Basically it is an order form that includes 6 categories, each of them having aprox. 20 items to choose from. I have created a multi page form, but my problem is that the grand total is shown for each category(page) and not the total amount of the order. Is there a way to carry the totatl of one page to the next one and show the grand total in the end?
    Sorry if this sounds stupid, I am a TOTAL nOOb to this.

    Thanks a million.
  • @Sirwani:

    The plug-in is design to just deal with data in the DOM. You could certainly do what you want to do, but you're going to need to persist the total from the previous page and use that in your calcuations.
  • Thank you Dan for your quick reply. Appreciate your continuous support for the plug-in. Let´s see if I can manage to do what I need on my own. :)
  • Great plugin. If I add reset button (<input type="reset" value="Reset!">), it clears the text boxes, but does not zero the grandTotal field. How can I do this?
  • @Wayne:

    You need to trigger the calculation when you click the reset button.
  • You just saved me a ton of time! thanks! :)
  • Thanks for your great plugin. I used for it for several pages and it has been very useful. I do have a question that has been giving me fits.

    I'm trying to get the results of calculations and them using those results to create sub totals and grand totals.

    Example:


    <input type="text" name="enterrate11" id="qty_item_11" id="price_item_11" class="input-mini" Value="00.56">
    <input type="text" name="qty_item_11miles11" id="qty_item_11" class="input-mini" Value="0">
    <input type="text" name="etsum_cartotal11" id="total_item_11" class="input-mini" value="0.00">

    <input type="text" name="enterrate12" id="qty_item_12" id="price_item_12" class="input-mini" Value="00.56">
    <input type="text" name="qty_item_11miles12" id="qty_item_12" class="input-mini" Value="0">
    <input type="text" name="etsum_cartotal12" id="total_item_12" class="input-mini" value="0.00">

    Using this function:
    $("input[name^=etsum]").sum("keyup", "#etttotalSum");
    Sub Total: <input type="text" name="carSubTotal" id="etttotalSum" size="2">
  • I do trust all of the ideas you have presented on your post.
    They're very convincing and will definitely work. Still, the posts are too short for newbies.
    May just you please lengthen them a bit from next time? Thank you
    for the post.

Comments for this entry have been disabled.