Home > Blockchain >  loop through an array of input names and sum the values of any radio buttons which are checked
loop through an array of input names and sum the values of any radio buttons which are checked

Time:05-21

I need to loop through an array of input names and sum the values of any radio buttons which are checked. I can get it to output a single group but am struggling to handle multiple groups values pulling back.

I used 'document.querySelector('input[name="star1"]:checked').value' to pull back a single value and output it. This worked fine but when i tried to implement it for 4 more additional groups I was getting error after error.

I decided to put the names of the groups into an array so i could loop through all 5 groups. I need it to ignore groups that have no radio button checked to avoid any null value errors.

EDITED: @Ruben - I have added the changes that you have suggested and although in logic it definitely seems to be what i am looking for, i still cant get this code to fire properly.

I have put the JS in a seperate .js file now and have included a script src link after the html.

var total_score;
var dict = {};

function scoreCount(value, name) {
  dict[name] = parseInt(value);
  total_score = 0;
  for (var score of Object.values(dict)) {
    total_score  = score;
  }
}
document.getElementById("star-text").innerHTML = total_score   "/25"; //my output
<form  type="text">
  <div >
    <h4>Question 1</h4>
  </div>
  <div >
    <h4>Question 2</h4>
  </div>
  <div >
    <h4>Question 3</h4>
  </div>
  <div >
    <h4>Question 4</h4>
  </div>
  <div >
    <h4>Question 5</h4>
  </div>
  <div >
    <input type="radio" name="star1" id="rad-5" value="5" onclick="scoreCount(value, name)"><label for="rad-5">
                                            </label>
    <input type="radio" name="star1" id="rad-4" value="4" onclick="scoreCount(value, name)"><label for="rad-4">
                                            </label>
    <input type="radio" name="star1" id="rad-3" value="3" onclick="scoreCount(value, name)"><label for="rad-3">
                                            </label>
    <input type="radio" name="star1" id="rad-2" value="2" onclick="scoreCount(value, name)"><label for="rad-2">
                                            </label>
    <input type="radio" name="star1" id="rad-1" value="1" onclick="scoreCount(value, name)"><label for="rad-1">
                                            </label>
  </div>
  <div >
    <input type="radio" name="star2" id="rad-6" value="5" onclick="scoreCount(value, name)"><label for="rad-6">
                                            </label>
    <input type="radio" name="star2" id="rad-7" value="4" onclick="scoreCount(value, name)"><label for="rad-7">
                                            </label>
    <input type="radio" name="star2" id="rad-8" value="3" onclick="scoreCount(value, name)"><label for="rad-8">
                                            </label>
    <input type="radio" name="star2" id="rad-9" value="2" onclick="scoreCount(value, name)"><label for="rad-9">
                                            </label>
    <input type="radio" name="star2" id="rad-10" value="1" onclick="scoreCount(value, name)"><label for="rad-10">
                                            </label>
  </div>
  <div >
    <input type="radio" name="star3" id="rad-11" value="5" onclick="scoreCount(value, name)"><label for="rad-11">
                                            </label>
    <input type="radio" name="star3" id="rad-12" value="4" onclick="scoreCount(value, name)"><label for="rad-12">
                                            </label>
    <input type="radio" name="star3" id="rad-13" value="3" onclick="scoreCount(value, name)"><label for="rad-13">
                                            </label>
    <input type="radio" name="star3" id="rad-14" value="2" onclick="scoreCount(value, name)"><label for="rad-14">
                                            </label>
    <input type="radio" name="star3" id="rad-15" value="1" onclick="scoreCount(value, name)"><label for="rad-15">
                                            </label>
  </div>
  <div >
    <input type="radio" name="star4" id="rad-16" value="5" onclick="scoreCount(value, name)"><label for="rad-16">
                                            </label>
    <input type="radio" name="star4" id="rad-17" value="4" onclick="scoreCount(value, name)"><label for="rad-17">
                                            </label>
    <input type="radio" name="star4" id="rad-18" value="3" onclick="scoreCount(value, name)"><label for="rad-18">
                                            </label>
    <input type="radio" name="star4" id="rad-19" value="2" onclick="scoreCount(value, name)"><label for="rad-19">
                                            </label>
    <input type="radio" name="star4" id="rad-20" value="1" onclick="scoreCount(value, name)"><label for="rad-20">
                                            </label>
  </div>
  <div >
    <input type="radio" name="star5" id="rad-21" value="5" onclick="scoreCount(value, name)"><label for="rad-21">
                                            </label>
    <input type="radio" name="star5" id="rad-22" value="4" onclick="scoreCount(value, name)"><label for="rad-22">
                                            </label>
    <input type="radio" name="star5" id="rad-23" value="3" onclick="scoreCount(value, name)"><label for="rad-23">
                                            </label>
    <input type="radio" name="star5" id="rad-24" value="2" onclick="scoreCount(value, name)"><label for="rad-24">
                                            </label>
    <input type="radio" name="star5" id="rad-25" value="1" onclick="scoreCount(value, name)"><label for="rad-25">
                                            </label>
  </div>
</form>

<div >
  <!--<label  name="score-star">
                        </label>-->
  <p  id="star-text">0/25</p>
</div>

<script src="/static/score.js"></script>

CodePudding user response:

The reason why you are getting an error with the loop you are using is because whenever u click a button, it will try to get the value of all buttons (which are not clicked yet at that time).

An easier way to do this, would be to just pass the value of the button in the onclick event. I added this in the html. I also passed the name to make sure only 1 score counts per question.

<form  type="text">
    <div >
      <h4>Question 1</h4>
    </div>
    <div >
      <h4>Question 2</h4>
    </div>
    <div >
      <h4>Question 3</h4>
    </div>
    <div >
      <h4>Question 4</h4>
    </div>
    <div >
      <h4>Question 5</h4>
    </div>
    <div >
      <input type="radio" name="star1" id="rad-5" value="5" onclick="scoreCount(value, name)"><label for="rad-5">
                                              </label>
      <input type="radio" name="star1" id="rad-4" value="4" onclick="scoreCount(value, name)"><label for="rad-4">
                                              </label>
      <input type="radio" name="star1" id="rad-3" value="3" onclick="scoreCount(value, name)"><label for="rad-3">
                                              </label>
      <input type="radio" name="star1" id="rad-2" value="2" onclick="scoreCount(value, name)"><label for="rad-2">
                                              </label>
      <input type="radio" name="star1" id="rad-1" value="1" onclick="scoreCount(value, name)"><label for="rad-1">
                                              </label>
    </div>
    <div >
      <input type="radio" name="star2" id="rad-6" value="5" onclick="scoreCount(value, name)"><label for="rad-6">
                                              </label>
      <input type="radio" name="star2" id="rad-7" value="4" onclick="scoreCount(value, name)"><label for="rad-7">
                                              </label>
      <input type="radio" name="star2" id="rad-8" value="3" onclick="scoreCount(value, name)"><label for="rad-8">
                                              </label>
      <input type="radio" name="star2" id="rad-9" value="2" onclick="scoreCount(value, name)"><label for="rad-9">
                                              </label>
      <input type="radio" name="star2" id="rad-10" value="1" onclick="scoreCount(value, name)"><label for="rad-10">
                                              </label>
    </div>
    <div >
      <input type="radio" name="star3" id="rad-11" value="5" onclick="scoreCount(value, name)"><label for="rad-11">
                                              </label>
      <input type="radio" name="star3" id="rad-12" value="4" onclick="scoreCount(value, name)"><label for="rad-12">
                                              </label>
      <input type="radio" name="star3" id="rad-13" value="3" onclick="scoreCount(value, name)"><label for="rad-13">
                                              </label>
      <input type="radio" name="star3" id="rad-14" value="2" onclick="scoreCount(value, name)"><label for="rad-14">
                                              </label>
      <input type="radio" name="star3" id="rad-15" value="1" onclick="scoreCount(value, name)"><label for="rad-15">
                                              </label>
    </div>
    <div >
      <input type="radio" name="star4" id="rad-16" value="5" onclick="scoreCount(value, name)"><label for="rad-16">
                                              </label>
      <input type="radio" name="star4" id="rad-17" value="4" onclick="scoreCount(value, name)"><label for="rad-17">
                                              </label>
      <input type="radio" name="star4" id="rad-18" value="3" onclick="scoreCount(value, name)"><label for="rad-18">
                                              </label>
      <input type="radio" name="star4" id="rad-19" value="2" onclick="scoreCount(value, name)"><label for="rad-19">
                                              </label>
      <input type="radio" name="star4" id="rad-20" value="1" onclick="scoreCount(value, name)"><label for="rad-20">
                                              </label>
    </div>
    <div >
      <input type="radio" name="star5" id="rad-21" value="5" onclick="scoreCount(value, name)"><label for="rad-21">
                                              </label>
      <input type="radio" name="star5" id="rad-22" value="4" onclick="scoreCount(value, name)"><label for="rad-22">
                                              </label>
      <input type="radio" name="star5" id="rad-23" value="3" onclick="scoreCount(value, name)"><label for="rad-23">
                                              </label>
      <input type="radio" name="star5" id="rad-24" value="2" onclick="scoreCount(value, name)"><label for="rad-24">
                                              </label>
      <input type="radio" name="star5" id="rad-25" value="1" onclick="scoreCount(value, name)"><label for="rad-25">
                                              </label>
    </div>
</form>

Your Javascript would look something like this:

var total_score;
var dict = {};
function scoreCount(value, name) {
  dict[name] = parseInt(value);
  total_score = 0;
  for (var score of Object.values(dict)){
        total_score  = score;
  }
}

Each time u click a button now, it will add a pair to the dict or replace it if it already exists and recalculate the total score based on the new dict.

CodePudding user response:

HTMLFormElement and HTMLFormControlsCollection interfaces are used to reference <form> and form controls.

// Reference a <form> with id (or name) "ratings"
const ratings = document.forms.ratings;
/*
Reference a form control inside of <form> with the id/name of "total". Assign it's value
as two spaces.
*/
ratings.total.value = "\u00A0\u00A0";

Don't use inline event handlers use onevent properties or event listeners, here's an onevent property:

/*
Bind "input" event to <form> invoke scoreCount(e) when "input" event is 
triggered on or within <form>. If any radio button is clicked, scoreCount(e) 
runs. A single line for an unlimited number of form controls. Don't waste your
time typing: onclick="scoreCount(value, name)" 25 times.
*/
ratings.oninput = scoreCount;

Events can bubble from one tag to it's parent and so on making this possible. Indirectly controlling many tags by listening for events with an ancestor tag and excluding and including tags in the event handler is called event delegation. Here's an event handler:

/*
All event handlers pass the Event Object by default. It isn't being used this
time. Instead, "this" is being used which points to the tag bound to the event
which is <form>. 
*/
function scoreCount(e) {
  // Reference all form controls within <form>
  const IO = this.elements;
  let score = 
    /*
    NodeList of all .checked tags within <form> converted into an array. The
    output will be coerced into a string ('' )
    */  
    ''   [...this.querySelectorAll(':checked')]
    /*
    On each iteration get the .checked tag's value and coerce it into a ( )
    number. Add that number to the accumulator (sum) (initial value is 0.
    */
    .reduce(
      (sum, chk) => sum   ( chk.value), 0);
    /*
    Take the output from the previous process and display it in <output>. The
    .padStart() keeps a space before the value so there isn't any shifting.
    */
    IO.total.value = score.padStart(2, "\u00A0");
  }

<!DOCTYPE html>
<html lang="en">

<head>
  <title></title>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <style>
    html {
      font: 300 2ch/1.25 'Segoe UI'
    }
    
    ol {
      padding-left: 20px;
    }
    
    li {
      margin-top: 8px;
    }
    
    li::marker {
      font-size: 1.1rem;
    }
    
    p {
      margin-bottom: 8px;
      font-size: 1.1rem;
    }
    
    fieldset {
      display: flex;
      justify-content: space-evenly;
      align-items: center;
    }
    
    fieldset label:first-of-type {
      order: 5
    }
    
    fieldset label:nth-of-type(2) {
      order: 4
    }
    
    fieldset label:nth-of-type(3) {
      order: 3
    }
    
    fieldset label:nth-of-type(4) {
      order: 2
    }
    
    fieldset label:last-of-type {
      order: 1
    }
    
    label {
      display: inline-block;
      font-size: 2rem;
      text-shadow: -1px -1px 1px rgba(255, 255, 255, .1), 
                   1px 1px 1px rgba(0, 0, 0, .5), 
                   2px -9px 2px rgba(221, 231, 255, 0);
      color: #d9d9d9;
      transition: 0.7s;
      cursor: pointer;
    }
    
    input {
      display: none;
    }
    
    input:checked~label {
      text-shadow: 2px 1px 0px #7A7A7A;
      color: #FFF900;
      transition: 0.7s
    }
    
    #total {
      display: block;
      font-family: Consolas;
      font-size: 1.25rem;
    }
    
    #total::before {
      content: 'Rating: ';
      font-family: 'Segoe UI';
    }
    
    #total::after {
      content: '/25'
    }
  </style>
</head>

<body>
  <form id='ratings'>
    <ol>
      <li>
        <p>Question 1</p>
        <fieldset name="rating">
          <input id="rad-5" name="star1" type="radio" value="5">
          <label for="rad-5">★</label>
          <input id="rad-4" name="star1" type="radio" value="4">
          <label for="rad-4">★</label>
          <input id="rad-3" name="star1" type="radio" value="3">
          <label for="rad-3">★</label>
          <input id="rad-2" name="star1" type="radio" value="2">
          <label for="rad-2">★</label>
          <input id="rad-1" name="star1" type="radio" value="1">
          <label for="rad-1">★</label>
        </fieldset>
      </li>
      <li>
        <p>Question 2</p>
        <fieldset name="rating">
          <input id="rad-10" name="star2" type="radio" value="5">
          <label for="rad-10">★</label>
          <input id="rad-9" name="star2" type="radio" value="4">
          <label for="rad-9">★</label>
          <input id="rad-8" name="star2" type="radio" value="3">
          <label for="rad-8">★</label>
          <input id="rad-7" name="star2" type="radio" value="2">
          <label for="rad-7">★</label>
          <input id="rad-6" name="star2" type="radio" value="1">
          <label for="rad-6">★</label>
        </fieldset>
      </li>
      <li>
        <p>Question 3</p>
        <fieldset name="rating">
          <input id="rad-15" name="star3" type="radio" value="5">
          <label for="rad-15">★</label>
          <input id="rad-14" name="star3" type="radio" value="4">
          <label for="rad-14">★</label>
          <input id="rad-13" name="star3" type="radio" value="3">
          <label for="rad-13">★</label>
          <input id="rad-12" name="star3" type="radio" value="2">
          <label for="rad-12">★</label>
          <input id="rad-11" name="star3" type="radio" value="1">
          <label for="rad-11">★</label>
        </fieldset>
      </li>
      <li>
        <p>Question 4</p>
        <fieldset name="rating">
          <input id="rad-20" name="star4" type="radio" value="5">
          <label for="rad-20">★</label>
          <input id="rad-19" name="star4" type="radio" value="4">
          <label for="rad-19">★</label>
          <input id="rad-18" name="star4" type="radio" value="3">
          <label for="rad-18">★</label>
          <input id="rad-17" name="star4" type="radio" value="2">
          <label for="rad-17">★</label>
          <input id="rad-16" name="star4" type="radio" value="1">
          <label for="rad-16">★</label>
        </fieldset>
        <li>
          <p>Question 5</p>
          <fieldset name="rating">
            <input id="rad-25" name="star5" type="radio" value="5">
            <label for="rad-25">★</label>
            <input id="rad-24" name="star5" type="radio" value="4">
            <label for="rad-24">★</label>
            <input id="rad-23" name="star5" type="radio" value="3">
            <label for="rad-23">★</label>
            <input id="rad-22" name="star5" type="radio" value="2">
            <label for="rad-22">★</label>
            <input id="rad-21" name="star5" type="radio" value="1">
            <label for="rad-21">★</label>
          </fieldset>
        </li>
    </ol>
    <fieldset>
      <output id='total'></output>
    </fieldset>
  </form>
  <script>
    const ratings = document.forms.ratings;
    ratings.oninput = scoreCount;
    ratings.total.value = "\u00A0\u00A0";

    function scoreCount(e) {
      const IO = this.elements;
      let score = 
        ''   [...this.querySelectorAll(':checked')]
        .reduce(
          (sum, chk) => sum   ( chk.value), 0);
      IO.total.value = score.padStart(2, "\u00A0");
    }
  </script>
</body>

</html>

  • Related