Reputation: 67
I have a little piece of jQuery code which calculates the recipe ingredients as per given serving, but somewhere it's not working properly.
My code is like this:
Serving: <input type="text" name="serving" class="serving" value="5" /> persons
<input type="hidden" id="previousServing" value="5"/>
<h3>ingredients</h3>
<ul class="ingredients">
<li class="ingredient">
<span class="amount">1</span> cups
<span class="name"><a href="http://www.mysite.com/ingredient/yogurt/">yogurt</a></span>
</li>
<li class="ingredient">
<span class="amount">2</span> tbsp
<span class="name"><a href="http://www.mysite.com/ingredient/yogurt/">chillies</a></span>
</li>
<li class="ingredient">
<span class="amount">3</span> pieces
<span class="name"><a href="http://www.mysite.com/ingredient/yogurt/">butter</a></span>
</li>
</ul>
$(function() {
$('.serving').bind('keyup', function(event) {
var previousValue = parseFloat($("#previousServing").val());
var newValue = parseFloat($(event.target).val());
if (previousValue && newValue) {
$('.ingredient').each(function(index, elem) {
var ingredientNow = $('.amount', elem);
var oldIngredientAmount = ingredientNow.text();
var newIngredientAmount = oldIngredientAmount * newValue / previousValue;
ingredientNow.text(newIngredientAmount);
});
$('#previousServing').val(newValue);
}
});
});
http://jsfiddle.net/vansimke/tLWpr/
issues:
Required: either no decimals or round to absolute two digit, i.e., 2.08 should be 2.00.
Thanks in anticipation.
Upvotes: 1
Views: 482
Reputation: 2566
First Problem: Significant figures and rounding
You need to times newIngredientAmount
to get a number of sigfigs then use Math.round
to round it to the nearest integer. Then divide the result by the number you multiplied by earlier
Added this line
newIngredientAmount = Math.round(newIngredientAmount * 100) / 100;
To create
$(function() {
$('.serving').bind('keyup', function(event) {
var previousValue = parseFloat($("#previousServing").val());
var newValue = parseFloat($(event.target).val());
if (previousValue && newValue) {
$('.ingredient').each(function(index, elem) {
var ingredientNow = $('.amount', elem);
var oldIngredientAmount = ingredientNow.text();
var newIngredientAmount = oldIngredientAmount * newValue / previousValue;
newIngredientAmount = Math.round(newIngredientAmount * 100) / 100;
ingredientNow.text(newIngredientAmount);
});
$('#previousServing').val(newValue);
}
});
Second Problem: Jquery .data(key, value) solution
The problem you have with the decimal hanging around is a problem due to rounding and oldIngredientAmount * newValue / previousValue
because some of these values could have been rounded. It seems to me that this is a bad way going about calulating the ingredient amount. You should instead by basing the math off of the inital ingredient ratios instead of the rounded derived numbers you calculate. You could use jquery .data()
to record the inital values in the amount spans and do math off those numbers each time.
Fiddler with .data()
to preserve the initial ratio and use that in the math
$(function() {
$('.ingredient').each(function(index, elem){
$this = $(this);
$this.data('init', parseFloat($this.text()));
});
$('#previousServing').data('init', parseFloat($('#previousServing').val()));
$('.serving').bind('keyup', function(event) {
var previousValue = $("#previousServing").data('init');
var newValue = parseFloat($(event.target).val());
if (previousValue && newValue) {
$('.ingredient').each(function(index, elem) {
var ingredientNow = $('.amount', elem);
var initIngredientAmount = $(this).data('init');
var newIngredientAmount = initIngredientAmount * newValue / previousValue;
newIngredientAmount = Math.round(newIngredientAmount * 100) / 100;
ingredientNow.text(newIngredientAmount);
});
$('#previousServing').val(newValue);
}
});
});
Upvotes: 2
Reputation: 70
Math.round(newIngredientAmount)
will round the number for you.
However, I just played around with your code. I don't think it's reliable for you to use the previously calculated value, especially if you're rounding it. That will mess up all your ingredient ratios.
This is what I would do
Serving: <input type="text" name="serving" class="serving" value="5" /> persons
<input type="hidden" id="defaultServing" value="5"/>
<h3>ingredients</h3>
<ul class="ingredients">
<li class="ingredient">
<span class="amount" defaultAmount="1">1</span> cups
<span class="name"><a href="http://www.mysite.com/ingredient/yogurt/">yogurt</a></span>
</li>
<li class="ingredient">
<span class="amount" defaultAmount="2">2</span> tbsp
<span class="name"><a href="http://www.mysite.com/ingredient/yogurt/">chillies</a></span>
</li>
<li class="ingredient">
<span class="amount" defaultAmount="3">3</span> pieces
<span class="name"><a href="http://www.mysite.com/ingredient/yogurt/">butter</a></span>
</li>
</ul>
$(function() {
$('.serving').bind('keyup', function(event) {
var previousValue = parseFloat($("#defaultServing").val());
var newValue = parseFloat($(event.target).val());
if (previousValue && newValue) {
$('.ingredient').each(function(index, elem) {
var ingredientNow = $('.amount', elem);
var oldIngredientAmount = ingredientNow.attr("defaultAmount");
var newIngredientAmount = oldIngredientAmount * newValue / previousValue;
// no decimal places
// ingredientNow.text(Math.round(newIngredientAmount));
// two decimal places
ingredientNow.text(Math.round(newIngredientAmount*100)/100);
});
}
});
});
Upvotes: 0