A jQuery plugin to do math with form fields, and put results in other fields.
This code is known to work in the following browsers:
- Firefox 18
- Chrome 40
- Internet Explorer 9
- Safari 8
- Opera 27
This library requires jQuery (v1.7.0+) and MathJS (v1.2.0). Reference these dependencies in your HTML before this library:
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/1.2.0/math.min.js"></script>
<script src="calculate.jquery.js"></script>
You can grab the calculate.jquery.js
file from src/calculate.jquery.js.
Take the following HTML:
<div class="basics">
<p><input class="base" value="12.2"> Base</p>
<p><input class="diff" value="5.1"> Difference</p>
<p class="total-wrap"><input class="total"> Total</p>
</div>
And the following JavaScript:
$('.basics').calculate('{{.total}} = {{.base}} - {{.diff}}');
As a result, you can expect:
- The field
.total
will be calculated automatically, given the value"7.1"
- A change in any of
.base
or.diff
(ie: achange
event) will result in an updated.total
- In turn, an auto-updated
.total
will trigger achange
event itself
This plugin is invoked with a formula to be applied to some selectors. These selectors will match descendants of the original jQuery object.
Each operand in the formula can actually refer to several elements. If this is the case, their values will be added up before resolving the rest of the formula. Example:
<div class="one-to-many">
<p><input class="operand" value="14"></p>
<p><input class="operand" value="1"></p>
<p><input class="operand" value="0.8"></p>
<p><input class="product" value="4"></p>
<p class="total-wrap"><input class="total"> Total</p>
</div>
With JavaScript:
$('.one-to-many').calculate('{{.total}} = {{.operand}} * {{.product}}');
The values of the .operand
elements will be added up (totalling 15.8). This is then multiplied by .product
, yielding a result of 63.2, which will be set as the value of .total
.
If the base jQuery object matches several elements, the expression will be run in each one of them. Example:
<div class="many-to-many">
<div class="one">
<p><input class="base" value="12.3"> Base</p>
<p><input class="diff" value="5.4"> Difference</p>
<p class="total-wrap"><input class="total"> Total</p>
</div>
<div class="one">
<p><input class="base" value="4"> Base</p>
<p><input class="diff" value="9"> Difference</p>
<p class="total-wrap"><input class="total"> Total</p>
</div>
</div>
With JavaScript:
$('.many-to-many .one').calculate('{{.total}} = {{.base}} - {{.diff}}');
Each individual .total
will be calculated within the context of each .many-to-many .one
.
You may want to preprocess the input fields before they are used. To do this, provide the option inputParser
.
For example, the number 1234567.89 can be written as "1,234,567.89" or "1.234.567,89" depending on the locale. This HTML uses Spanish formatting:
<div class="custom-input">
<p><input class="base" value="1.234.567,89"> Base</p>
<p><input class="diff" value="5,89"> Difference</p>
<p class="total-wrap"><input class="total"> Total</p>
</div>
With JavaScript:
var esInputParser = function (rawVal) {
var pair = rawVal.split(',');
var integer = pair[0].replace(/\./g, '');
var decimal = pair[1] || '0';
return (integer + '.' + decimal)*1;
};
$('.custom-input').calculate('{{.total}} = {{.base}} - {{.diff}}', { inputParser: esInputParser });
Similarly, you may want to process the results to format them in a specific way.
Take this HTML:
<div class="custom-output">
<p><input class="base" value="12.2"> Base</p>
<p><input class="diff" value="5.1"> Difference</p>
<p class="total-wrap"><input class="total"> Total</p>
</div>
With this JS:
var outputFormatter = function (result) {
return result.toFixed(2);
};
$('.custom-output').calculate('{{.total}} = {{.base}} - {{.diff}}', { outputFormatter: outputFormatter });
As a result, the value of .total
will be formatted with two decimals, rounding when appropriate.
It's possible to set default values for options (at the moment these are only inputParser
and outputFormatter
). To do so, use $.calculate.options(defaults)
, like so:
$.calculate.options({
inputParser: function() { ... },
outputFormatter: function() { ... }
});
Any subsequent invocations of the plugin will use those options.
Instances of the calculator offer an API. This can be used to cover more advanced cases. To use the API, call calculate()
with a function. This function will receive the api as first and only parameter:
$('.example').calculate(function(api) {
// Do stuff with `api` here
});
The interface is:
formula(newFormula)
: receives a string with a formula. This will replace the current formula for the calculatorrun()
: forces a recalculation
Additionally, within the function, this
will be the jQuery object on which calculate()
was called.
Sometimes, the formula to apply will not be static, and will depend on external factors. For example, the formula may change following a change on a checkbox. See this example:
<div class="api-formula">
<p><input class="base" value="12.2"> Base</p>
<p><input class="diff" value="5.1"> Difference</p>
<p class="total-wrap"><input class="total"> Total</p>
</div>
With this JS:
var api;
$('.api-formula').calculate(function(_api) {
api = _api;
});
api.formula('{{.total}} = {{.base}}');
// At this point, the value of `.total` will be '12.2'
api.formula('{{.total}} = {{.base}} - {{.diff}}');
// Now, `.total` will have a value of '7.1'
The plugin knows to remove unused event handlers when appropriate, avoiding memory leaks. Or so I hope!
Bug reports and contributions are welcome. Please check CONTRIBUTING.md.
Big props go to my employer: New Bamboo. This library was extracted from code of one of its projects. Additional work was also done on company time.
Copyright (C) 2015 Pablo Brasero Moreno
Licensed under the MIT License. See LICENSE.md for details.