Stack Exchange
Calculating sum of checked checkboxes
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?

What is calculator here?

Please post all of the relevant code including the definition of calculator.

Added calculator definition. Apologies for omission.

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>




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/

I really need help with the vanilla JavaScript version. Thanks for such a comprehensive answer!

This works with only JavaScript. It's less good, though. It relies on XPath, which is built into web browsers: https://jsfiddle.net/8tf25zw9/33/ There's still full separation of HTML and JavaScript. It could have been simpler, but I could not figure out how to select checked checkboxes with XPath.

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>




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>

