Checking radio boxes are selected using Javascript

Hi I’m trying to make sure radio boxes have been checked and if not then to throw an error message. Also to validate the correct answers. Any help would be appreciated.

The pen is located on codepen at:
e-learning example (codepen.io)

Currently, you are only checking the first set of radios buttons (the ones with name “group1”), so you will need to target the other radio button sets.

Why not use fieldset for each set of buttons and the use querySelectorAll('fieldset') to get all the sets and then use querySelectorAll('input[type=radio]') to get the radio buttons?

Hi Randall. Thank you thats a good solution. I’ve recently changed it so the function should check through each group seperately but it doesn’t work. is there a reason the following code doesn’t work??

function checks() {
  var check1 = document.getElementsByName("group1");
  for (var i = 0; i < check1.length; i++) {
    if (check1[i].type == "radio" && check1[i].checked) { return true; }
  }
  return document.getElementById("not_checked_group1").innerHTML = "PLEASE SELECT AN OPTION";
  
  var check2 = document.getElementsByName("group2");
  for (var i = 0; i < check2.length; i++) {
    if (check2[i].type == "radio" && check2[i].checked) { return true; }
  }
  return document.getElementById("not_checked_group2").innerHTML = "PLEASE SELECT AN OPTION"; 
}

As soon as a return statement is executed, the function is exited and processes no further code. Your current code will either exit in the first for loop or first return statement after the first for loop.

On a side note, I know you are just trying to get some code working for 4 questions, but imagine your quiz had 100 questions. Would you really want to hard code all of those checks and for loops? See if you can think of a way to structure your HTML, so that you are not targeting element id attributes.

This is the problem. I’m failing to see how this can be done with the one function, and after I would like to add the values to calculate a score

So if you make a few changes in the HTML like adding a class="answers-div" to each of the div elements that currently have an id like answers4-div, then you could get all of the radio button sets.

var radioSets = document.querySelectorAll(".answers-div");

Then you could iterate through this HTML Collection and get another HTML Collection of all the radio buttons for each radioSet.

var checkboxes = [ ...radioSet.querySelectorAll('input[type=radio]') ];

The next part is the key to it all. There are multiple ways of accomplishing it, but the easiest is to initialize a new variable to false. This variable will hold the status if any checkbox within a set of radio buttons has been found to have a check mark already. You start with false, because you have not checked anything yet and only want to do something if it is true. So now you iterate through the checkboxes. As soon as you find one that is checked, you assign the value true to your status variable and break out of the iteration (assuming you are using a for loop). After the loop ends, your status variable is either true or false.

If you add a p element with the text “PLEASE SELECT AN OPTION” at the end of each set of radio buttons (like you did with the first one) but instead of using an id, give it a class="not_checked_group" or something like that, then you could change your CSS so that:

#not_checked_group1, #not_checked_group2, #not_checked_group3, #not_checked_group4 {
  width: 60%;
  font-family: verdana;
  font-size: 1.5em;
  background-color: red;
  text-align: center;
  margin: auto auto;
}

becomes:

.not_checked_group {
  visibility: hidden;
  width: 60%;
  font-family: verdana;
  font-size: 1.5em;
  background-color: red;
  text-align: center;
  margin: auto auto;
}

Notice, the visibility property set to hidden. This is so you do not display this element by default.

In your CSS, you can add a new class named “show-message” or something similar that has only the following:

.show-message {
  visibility: visible;
}

Now, back in your JavaScript code, where your iteration of the checkboxes of a radio button set has completed, you can check if your status variable is true. If it is, then you would dynamically add the show-message class to the applicable p element within the div with class="answers-div". If the status variable is false, you remove this same class from the p element.

This will work with 4 questions or 1000 questions without having to hard code ids in the code.

Thank you. I’ve tweaked the HTML and CSS and I understand what this does. You’ve completely lost me with the Javascript. I’ve had an attempt but I don’t think I quite understand

e-learning example (codepen.io)

I also have values of false and true assigned to the radio buttons already to calculate the score.

You have the HTML almost as I specified above. For some reason, you have:

 <input id="q1 a1" type="radio" name="group1" value="fa.message-hidden {
  visibility: hidden;
}lse" />

when it should just be:

 <input id="q1 a1" type="radio" name="group1" value="false" />

For the CSS, you correctly changed the not_checked class. However, you only need one new class that you will add to the p element. You created:

.message-hidden {
  visibility: hidden;
}

You only need the one class named message-visible that when added to the p element, will make it visible.

As far as your JavaScript, you still need a function (named checks) to contain all the code needed need to hide/show the applicable p elements.

You correctly obtained the HTML collection of radio button sets, but then you did not iterate through them as I specified. Instead, you captured all of the checkboxes across all questions instead of just per question. Fix this first and then continue reading below.

I mentioned previously about needing a new variable being set to false. false is a Boolean value. You initialized your new variable to "False" which is a string. That is not the same thing. Also, you wrote:

return newVar = "True";

for the if statement code block. You do not want to use return here as the function will exit prematurely. You instead want to assign the new variable the Boolean value true and break out of the for loop. Read about using break in a loop.

Once that for loop completes

Okay. So the .message_visible class will overwrite all css from the .not_checked class as I’ve added all the css from the first to the second?? Here is what I have now:

function checks() {
  
  var radioSets = document.querySelectorAll(".answers-div");
  var radioButtons = [ ...radioSets.querySelectorAll('input[type=radio]') ];
  var newVar = false;
  var notChecked = document.querySelectorAll(".not_checked");

  for (var i = 0; i < radioButtons.length; i++) {
    if (radioButtons[i].type == "radio" && radioButtons[i].checked) { return true; }
    else if (radioButtons[i].type == "radio" && radioButtons[i].css == ".not_checked") {notChecked.toggleClass(".message_visible");  
  }   
}

I think I’m still confused on the initiation of the newVar to false

(post deleted by author)

Not sure why you have this line.

Also, you have a HTML collection radioSets that you should be iterating through. Nested inside that iteration will be another iteration through radioButtons.

The algorithm is:

1. Get all the radio button sets.

2. For each radio button set do the following:

     2.1 Get all the radio buttons within a radio button set.

     2.2 Initialize a variable to the value false to track status
         if any of the radio buttons in current radio button set
         have been checked.

     2.2 For each radio button do the following:

          2.2.1 If radio button is checked, then add the
                message-visible class to the p element within
                the radio button set div AND assign the value
                true to the status variable and do not check any
                more radio buttons in radio button set (break
                out of the iteration (not the function).

     2.3 Check the value of the status variable.  If the status
         variable value is true, this means the radio button set
         has one checked button, so you should remove the
         message-visible class from the p element (in case there
         is one there).  If the status variable is false, this
         means the radio button set does not have any button
        checked, so you should add the message-visible class to
        the p element.

EDIT: If you are still confused about the status variable, review solution #4 in the Guide for the Wherefore Art Thou challenge to see how the found status variable was used. The if statement condition and code block are different, but the concept is the same.

Thank you for the detailed explanation and structure of the algorithm. I think in the following code I have the methods wrong and too many if statements but it’s getting there. I do understand the value of the true and false boolean but was expecting to use it to verify the correct answers, although your explanation will help to solve this also. I am struggling to target the p elements individually here though

function checks() {
  
  var radioSets = document.querySelectorAll(".answers-div");
  var radioButtons = [ ...radioSets.querySelectorAll('input[type=radio]') ];
  var newVar = false;
  

  for (var i = 0; i < radioButtons.length; i++) {
    if (radioButtons[i].checked) { radioSets.add(".message_visible"); return newVar = true; break;}
   
   if (newVar.value == true) { radioButtons.class.remove(".message_visible"); }
   if (newVar.value == false) { radioButtons.class.add(".message_visible"); }
  }
}

newVar is just a Boolean variable. It does not have a property named value. You just reference newVar instead.

You are still trying to return a value which is not what the algorithm states. You need to carefully read through the algorithm again. Your if statement code block inside the for loop only needs to change the value of newVar and break out of the loop.

Then, after the for loop, that is where you actually check the value of newVar and either add or remove the message-visible class.

Is this better??

function checks() {
  
  var radioSets = document.querySelectorAll(".answers-div");
    forEach (i = 0; i < radioSets.length; i++) {
      var radioButtons = [ ...radioSets.querySelectorAll('input[type=radio]') ];
      var newVar = false; }
  
      for (var i = 0; i < radioButtons.length; i++) {
        if (radioButtons[i].checked) { radioSets.add(".message_visible"); { return newVar = true; break;}
   
    if (newVar == true) { radioButtons.class.remove(".message_visible"); }
    if (newVar == false) { radioButtons.class.add(".message_visible"); }
  }
}

Not sure why you insist on returning a value within the for loop.

Aldo, I would recommend changing the name of the status variable from newVar to something the actual describes the status you are trying to check. For example, you are trying to check if one of the radio buttons in the set is checked, so why not name it isChecked or foundCheck? You always want variable names that make your code easier to read and understand. A variable named newVar does explain anything.

Lastly, don’t try to put all the code on one line. It is much more readable to see the nested structure of the if statements:

Intstead of:

    if (newVar == true) { radioButtons.class.remove(".message_visible"); }
    if (newVar == false) { radioButtons.class.add(".message_visible"); }

write:

    if (newVar == true) {
      radioButtons.class.remove(".message_visible");
    }
    if (newVar == false) {
      radioButtons.class.add(".message_visible");
    }

Also, since newVar can only be either true or false, why not use an if/else statement instead of two if statements?

So the return newVar = true is completely unnecessary?

As I have explained several times now, when a return statement executes, the function is exited immediately. You do not want to exit the function. You just want to change the value of newVar and break out of the for loop.

Sorry I am paying attention. I decided to learn some python on another course and then go back to practice the Javascript again. I feel like I havn’t targeted the <p> elements properly. and also I have a syntax error on the for each statement line

function checks() {
  
  var radioSets = document.querySelectorAll(".answers-div");
    forEach (i = 0; i < radioSets.length; i++) {
      var radioButtons = [ ...radioSets.querySelectorAll('input[type=radio]') ];
      var newVar = false; }
  
      for (var i = 0; i < radioButtons.length; i++) {
        if (radioButtons[i].checked) { 
          radioSets.add(".message_visible"); 
          newVar = true; 
          break;
        }
   
    if (newVar == true) { 
      radioButtons.class.remove(".message_visible");
    }
    if else (newVar == false) { 
      radioButtons.class.add(".message_visible"); 
    }
  }
}

I will change newVar to something else

You have a stray } here that should not be there. Also you are missing a ) that completes the forEach.

While iterating through radioButtons array and find a radio button with a check mark, do you want to make the p element message show?