jQuery Calculation Plug-in: Making calculating easy...
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:
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:
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:
<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:
$("input[@name^=qty_item_]").bind("keyup", recalc);
Our recalc() function looks like this:
// 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
Comments
I just checked this in IE7 and it's working fine for me. Is there something specific that's not working for you?
if tested with your demo link and nothing (calculations) it´s working, but it works fine on FF.
regards,
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.
...and what might be filtering/blocking ?
i don´t have any firewall installed and i´ve stopped my anti-virus also.
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.
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. :)
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
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.
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.
Thanks for the nice plug-in.
How to calculate the time can u pl give an idea
Thanks
Venkat
:)
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".)
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!
What's your code look like, is there an example I can see? Also, what problem are you having?
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
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
Take a look at the example of the shopping cart and look at the code for the calc() method. It shows off similar functionality.
Thanks, hal
You should do the calculations on the server side. Never trust data coming from the client.
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 !!!
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.
$("input[@name^=input_]").sum({bind:"keyup",oncalc:myOnCalc}, "#som");
Thanks !
function formatTotals(s, opt) { return s.toFixed(2); // test }
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]").
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!
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.
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.
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 want to use the grandTotal as a value of an input area. I've tried everything I can but can't work. Any idea :(
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.
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.
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.
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.
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
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
}
);
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.
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.
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!!
See this comment for how to use European formatted numbers:
http://blog.pengoworks.com/index.cfm/2008/2/20/Wat...
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
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?
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.
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?
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.
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.
Sorry for all the noise.
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.
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.
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.
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.
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...?
If you change:
$(document).ready(function(){
to:
$(window).load(function(){
Does it work?
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
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.
Could you be more explicit about the actual problem you're having?
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
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();
}
);
}
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
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.
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
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 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.
https://www.psd2html.com/order-now.html
when you change the order details with radio buttons the total price will change too
Thanks !
I know what you want and the calc plug-in will work, but you must use the field plug-in.
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.
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.
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.
$(function() {
var line_items = $("input[name^=opportunity[line_items_attributes]][name$=[value]]").live("keyup", function(){
var sum = line_items.sum();
$("#totalSum").val(sum);
});
});
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.
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);
});
});
cameron
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"
);
});
}
);
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.
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.
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.
$("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.
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.
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.
$(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.
When you add new rows, you'll also need to invoke the $.sum() call on the new rows.
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.
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>
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
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>
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);
}
);
}
}
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)
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
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.
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;
},
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()'
$('#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.
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".)
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);
}
);
}
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.
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
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.
You'll need to use the calc() method--or just manually perform the math on a callback.
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.
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.
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
Just use the calc() method to perform the calculation.
-Dan
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
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.
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
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.
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.
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
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.
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.
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.
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.
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
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 );
});
});

this plug-in doesn´t work on IE 7.
regards,
Rui