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)
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 id
s 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
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?