Reputation: 4789
I would like to calculate the sum of checked checkboxes and print the result to the form input value, but this code isn't working:
var calculator = document.querySelector("form");
function extras() {
var extrasPricing = new Array();
extrasPricing["candles"] = 5;
extrasPricing["inscription"] = 10;
extrasPricing["decoration"] = 25;
extrasPricing["special"] = 50;
var extrasCost = 0;
var extras = calculator.elements["extras"];
for (var i = 0; i < extras.length; i++) {
if (extras[i].checked) {
extrasCost = extrasCost + extrasPricing[extras[i].value];
break;
}
}
return extrasCost;
}
function calculateTotal() {
calculator.total.value = "$" + extras();
}
<form>
<fieldset>
<legend>Select Extras</legend>
<label><input type="checkbox" name="extras" value="candles" onclick="calculateTotal()">Candles</label><br>
<label><input type="checkbox" name="extras" value="inscription" onclick="calculateTotal()">Inscription</label><br>
<label><input type="checkbox" name="extras" value="decoration" onclick="calculateTotal()">Decoration</label><br>
<label><input type="checkbox" name="extras" value="special" onclick="calculateTotal()">Special Frosting & Icing</label>
</fieldset>
<input type="text" name="total" readonly>
<input type="submit" value="Submit">
</form>
What am I doing wrong while performing the calculation?
Upvotes: 2
Views: 1849
Reputation: 963
As noted by others, your extrasPricing
does need to be an object to more easily access it. You can also you documentQuerySelectorAll with your CSS selectors to select your checked elements.
The '...' is a spread operator that converts a NodeList (which is returned with documentQuerySelectorAll) to an array, which is then able to use the various array methods to map the values to a new array, then reduce the values to a total.
Reduce throws an error if the array is empty, so the ternary operator is used to return the reduce output if the array has an element (extrasCost.length > 0)
, or to return 0
if the array is empty.
function extras() {
const extrasPricing = {
candles: 5,
inscription: 10,
decoration: 25,
special: 50,
};
let extrasCost = [...document.querySelectorAll('input[name=extras]:checked')]
.map((el) => extrasPricing[el.value])
return extrasCost.length > 0 ? extrasCost.reduce((total, num) => total + num) : 0;
}
function calculateTotal() {
calculator.total.value = '$' + extras();
}
<form>
<fieldset>
<legend>Select Extras</legend>
<label><input type="checkbox" name="extras" value="candles" onclick="calculateTotal()">Candles</label><br>
<label><input type="checkbox" name="extras" value="inscription" onclick="calculateTotal()">Inscription</label><br>
<label><input type="checkbox" name="extras" value="decoration" onclick="calculateTotal()">Decoration</label><br>
<label><input type="checkbox" name="extras" value="special" onclick="calculateTotal()">Special Frosting & Icing</label>
</fieldset>
<input type="text" name="total">
<input type="submit" value="Submit">
</form>
Upvotes: 1
Reputation: 301
Here's a working example of your code. There were a few syntax errors as well noted above by eje211.
var calculator = document.querySelector("form");
function extras() {
// Object vs Array
var extrasPricing = {
candles: 5,
inscription: 10,
decoration: 25,
special: 50
}
var extrasCost = 0;
var extras = document.getElementsByName("extras");
for (var i = 0; i < extras.length; i++) {
if (extras[i].checked) {
var val = extras[i].value;
// Update here to add/remove value of checked item to previous checked item.
extrasCost += extrasPricing[val];
}
}
return extrasCost;
}
function calculateTotal() {
calculator.total.value = "$" + extras();
}
<form>
<fieldset>
<legend>Select Extras</legend>
<label><input type="checkbox" name="extras" value="candles" onclick="calculateTotal()">Candles</label><br>
<label><input type="checkbox" name="extras" value="inscription" onclick="calculateTotal()">Inscription</label><br>
<label><input type="checkbox" name="extras" value="decoration" onclick="calculateTotal()">Decoration</label><br>
<label><input type="checkbox" name="extras" value="special" onclick="calculateTotal()">Special Frosting & Icing</label>
</fieldset>
<input type="text" name="total">
<input type="submit" value="Submit">
</form>
Upvotes: 1
Reputation: 89264
Remove the break
which will stop the for
loop. Your for
loop is only going to get the value of the first checked checkbox that way. Your logic is flawed; just because you have found one checked checkbox does not mean that your calculations are finished. You need to add the values of all the checked checkboxes.
var calculator = document.querySelector("form");
function extras() {
var extrasPricing = new Array();
extrasPricing["candles"] = 5;
extrasPricing["inscription"] = 10;
extrasPricing["decoration"] = 25;
extrasPricing["special"] = 50;
var extrasCost = 0;
var extras = calculator.elements["extras"];
for (var i = 0; i < extras.length; i++) {
if (extras[i].checked) {
extrasCost = extrasCost + extrasPricing[extras[i].value];
//Do not break here
}
}
return extrasCost;
}
function calculateTotal() {
calculator.total.value = "$" + extras();
}
<form>
<fieldset>
<legend>Select Extras</legend>
<label><input type="checkbox" name="extras" value="candles" onclick="calculateTotal()">Candles</label><br>
<label><input type="checkbox" name="extras" value="inscription" onclick="calculateTotal()">Inscription</label><br>
<label><input type="checkbox" name="extras" value="decoration" onclick="calculateTotal()">Decoration</label><br>
<label><input type="checkbox" name="extras" value="special" onclick="calculateTotal()">Special Frosting & Icing</label>
</fieldset>
<input type="text" name="total" readonly>
<input type="submit" value="Submit">
</form>
Upvotes: 1
Reputation: 2429
You seem to be coming from PHP.
There are several issues with your code.
In JavaScript, several data structures exist either as primitives or objects. In the case of the array, this is the primitive:
var anArray = [];
and this is the object:
var anArray = new Array();
when both exist, you should never use the object. It should only ever be used internally.
Also, JavaScript does not have associative arrays or dictionaries. It only has what it calls objects. Under the hood, they're the same thing, but what that means is:
colors["blue"]
and
colors.blue
are the same thing. When the second is possible, which is not always the case, the second form is preferred.
Now, for your HTML.
Don't use name
. name
is obsolete. Use either class
or id
. Here, you could use class
, but really, you don't need to. Putting an id
on the fieldset
element would probably be enough to get to your input
elements.
You should not write JavaScript inside of HTML. There are many solutions to that problem. The simplest is to simply use jQuery. If you do, it will be jQuery that will attach the callback to your HTML to keep the HML and JavaScript nice and separate. An ever better approach would be to use an even more complete framework such as React, Vue or Angular, but those can be more difficult to learn that can be overkill for now.
So, let's try jQuery instead.
Try this on for size: https://jsfiddle.net/8tf25zw9/3/
Upvotes: 2