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.

Comments
this plug-in doesn´t work on IE 7.
regards,
Rui
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.
regards,
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.
regards,
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".)