0

This question is NOT like this. The problem here is stemming from an if condition that is retaining a prior value, while the other question is asking how to determine what type of input is shown on screen.

<html>
    <head>
        <meta charset="utf-8">
        <title>Untitled Document</title>
        <script type="text/javascript">
            function displayquestion(a, ignore){
                var b = a-1;
                var currentInput = '';
                var questions = document.getElementsByClassName("questionholder");
                var showRequired = document.getElementById("requiredMessage");

                function showNext (){
                    showRequired.style.display = "none";        

                    for(var i=0; i < questions.length; i++) {           
                        questions[i].style.display = "none";    
                    }

                    var nextQuestion = document.getElementById("question" + a);

                    if(nextQuestion !== null) {
                        nextQuestion.style.display = "block";
                    }   
                }

                // Check if question should ignore inputs
                if (ignore == 1) { // yes, ignore the inputs so move on to next question
                    console.log("path 1");

                    showNext();

                } else { //no, don't ignore the inputs
                    if (document.querySelector('input.input' + b).type == "radio") { //this is a radio input                
                        if (document.querySelector('input[type=radio]:checked')) { //a radio option is selected
                            console.log("path 2");

                            showNext();

                        } else { // no radio option is selected so show error                   
                            console.log("path 3");

                            showRequired.style.display = "block";
                        }               
                    } else { // not a radio input
                        if (document.querySelector('input.input' + b) !== null) {
                            var currentInput = document.querySelector('input.input' + b).value;
                        }

                        if (currentInput == '') { // the input is blank so show error
                            console.log("path 4");

                            showRequired.style.display = "block";

                        } else { // the input is not blank so move on to next question
                            console.log("path 5");

                            showNext();
                        }
                    }
                }
            }   
        </script>
    </head>
    <body>
        <div id="requiredMessage" style="display:none">
            <p>This field is required.</p>
        </div>
        <form id="TheForm" style="display:block;">
            <div data-toggle="buttons" class="questionholder multiplechoice" id="question13" style="display:block">
                <h5>The world is... </h5>
                <input class="input13" type="radio" id="round" name="isPrevRel" value="round">
                <label for="round">
                    <p class="radioChoice">round</p>
                </label>
                <br>
                <input class="input13" type="radio" id="square" name="isPrevRel" value="square">
                <label for="birthcombo">
                    <p class="radioChoice">Square</p>
                </label>
                <br>
                <a class="text2button radio" onclick="displayquestion(14)">Next</a>
            </div>
            <div data-toggle="buttons" class="questionholder multiplechoice" id="question14" style="display:none">
                <h5>Do you like snow?</h5>
                <input class="input14" type="radio" id="yes" name="snow" value="yes">
                <label for="yes">
                    <p class="radioChoice">Yes. If you'd like, explain why</p>
                </label>
                <input class="input14" type="radio" id="no" name="snow" value="no">
                <label for="no">
                    <p class="radioChoice">No</p>
                </label>
                <br>
                <input name="relSNonID1"><br>
                <a class="text2button radio" onclick="displayquestion(15)">Next</a>
            </div>
        </form>
    </body>
</html>

I have issues with my javascript function, which works as intended with input text fields AND with radio buttons, but not when the two are combined.

In short, I have a div that asks a questions and contains a pair of radio buttons, a text input, and a next button. When the user click next, the function displayquestion(a) fires.

The function checks to see if it is told to ignore the current question. If so, it hides the div and displays the next question.

If not, it checks to see if the document contains an input with a class of input# (where # corresponds to the div id question#) is a radio input. If it is, it checks to see if an of the radio options is selected. If none are selected, it shows an error message.

Otherwise, if the input is not a radio input, it checks to see if the input is blank. If it is blank, it shows an error message. If it is not blank, it hides the div.

It works as intended but only if the shown div contains ONLY a radio option set OR a text input.

As you can see, I have one question where a radio option must be made, with an optional text input.

The intended result should be that the error message displays until the user makes a radio selection. it does not matter if the text input is completed. Only if a radio option is selected and when the user clicks next, it should hide the div.

Instead, what happens is that the div hides whether the user does nothing at all, or makes a choice.

From what I've gathered, the issue is stemming from

document.querySelector('input[type=radio]:checked')

Where it appears that the condition is retaining its value from question 13 (the first div) even when the user sees question 14 (the second div). I know this because the console log is printing the same values when clicking next on both divs.

I believe it is because i'm not checking for input + b but I am unable to add the varible. What is the proper integration?

jsfiddle

Alessandro Lodi
  • 544
  • 1
  • 4
  • 14
Sweepster
  • 1,829
  • 4
  • 27
  • 66
  • `document.querySelector('input[type=radio]:checked')` will select the **first** checked radio button out of **all** radio buttons in the page, not just the ones which happen to be currently visible. Invisible elements are still part of the page and the DOM. So if a previously answered question has a checked radio button, then that will be returned first, and give you a false positive. You need to narrow down your selector to the radio buttons within the div for your current question. I don't think the presence/absence of a text box has any relevance to this problem – ADyson Feb 06 '19 at 21:53
  • This: _it checks to see if an of the radio options is selected._ You want to check everything with a given classname but your query: `document.querySelector('input[type=radio]:checked')` will only ever return **the first** element that matches - not all of them. So use `document.querySelectorAll('input[type=radio]:checked')` instead. But you will also need to interate over them to determine _if any are checked_ – Randy Casburn Feb 06 '19 at 21:54
  • 1
    your code could also be simplified by using Live Node Lists rather than querying each time. Read this: https://stackoverflow.com/questions/28163033/when-is-nodelist-live-and-when-is-it-static – Randy Casburn Feb 06 '19 at 21:58
  • @ADyson I've identified this issue in description. My question however, is how to do this. Essentially, i need to combine document.querySelector('input.input' + b).type == "radio") with document.querySelector('input[type=radio]:checked') but how do I do this? – Sweepster Feb 06 '19 at 22:03
  • 1
    The only elements within your HTML that have class names of the pattern `input#` are checkboxes. So eliminate that test altogether. I would isolate. your valid test to the parent node of the checkbox you are seeking. – Randy Casburn Feb 06 '19 at 22:08
  • They are all radio buttons, not checkboxes.My HTML is far longer than shown but the issue is specific to this block. There are inputs that are text inputs. NONE are checkboxes. My code IS isolated.removing question 13 allows question 14 to function. See my earlier comment. The issue is I need to check if input with class =input+b is checked. I don't care which one is checked, only if that class is checked. – Sweepster Feb 06 '19 at 22:11
  • 1
    my bad, sorry; change my comment to read "radio buttons". Nothing else changes. This `document.querySelector('input.input' + b).type == "radio"'` is unnecessary, but you don't agree. OK. The next test: `document.querySelector('input[type=radio]:checked')` does exactly what ADyson's very first comment does. Soooo, I simply offer that you must either query the SPECIFIC singular radio button you want to test, or isolate your indeterminate test to the the smallest set of radio buttons possible **so that the `.querySelector()` can find the correct radio button to test**. – Randy Casburn Feb 06 '19 at 22:30
  • document.querySelector('input.input' + b).type == "radio" is necessary because that targets the VERY SPECIFIC input that contains the class name inputb (where b = the id of the div). I know the two checks are redundant, this is the third time now that I mention this and ask how they can be COMBINED. You tell me to target the specific singular radio button but don't show me how while I keep sayin I am trying only to target whether a SET of radio buttons is checked (are ANY buttons with the class name input b within question X checked, not is the yes radio button on question X checked) – Sweepster Feb 06 '19 at 23:06

1 Answers1

1

Your primary issue is that when you are testing for checked radio buttons, it checks across all radio buttons in the page, not just the ones which are in the currently visible question. It's not a case of the variable "retaining" its value, it's simply that the scope of the selector is too broad, and it will return the first selected checkbox it finds - in this case, there happens to already be one from a previous question, so it returns that.

A couple of small changes can a) make your code a bit more efficient (less repeated querying of the same thing, and b) resolve your issue

1) for efficiency and readability, put the result of document.querySelector('input.input' + b); into a variable so you don't have to run the same query repeatedly in the if statements

2) to check if a radio button is selected within the current question, add a restriction to the selector to narrow the scope into the current question: document.querySelector("#question" + b + " input[type=radio]:checked")

3) There was an error which prevented the "Square" option from being selected in the first question - the accompanying label's for attribute was wrong, it should be <label for="square">

By the way I don't think it's possible or desirable to combine the two tests (as you mention in the comments) because they don't do the same thing. The first test checks what kind of input the first input in the question is, and the second test checks the status of that input (once we know it's definitely a radio button).

Demo:

function displayquestion(a, ignore) {
  var b = a - 1;
  var currentInput = '';
  var questions = document.getElementsByClassName("questionholder");
  var showRequired = document.getElementById("requiredMessage");

  function showNext() {
    showRequired.style.display = "none";

    for (var i = 0; i < questions.length; i++) {
      questions[i].style.display = "none";
    }

    var nextQuestion = document.getElementById("question" + a);

    if (nextQuestion !== null) {
      nextQuestion.style.display = "block";
    }
  }

  // Check if question should ignore inputs
  if (ignore == 1) { // yes, ignore the inputs so move on to next question
    console.log("path 1");

    showNext();

  } else { //no, don't ignore the inputs
    var input = document.querySelector('input.input' + b);
    if (input.type == "radio") { //this is a radio input    
      if (document.querySelector("#question" + b + " input[type=radio]:checked")) { //a radio option is selected
        console.log("path 2");

        showNext();

      } else { // no radio option is selected so show error     
        console.log("path 3");

        showRequired.style.display = "block";
      }
    } else { // not a radio input
      if (input !== null) {
        var currentInput = input.value;
      }

      if (currentInput == '') { // the input is blank so show error
        console.log("path 4");

        showRequired.style.display = "block";

      } else { // the input is not blank so move on to next question
        console.log("path 5");

        showNext();
      }
    }
  }
}
body {
  font-family: arial;
}

h1 {
  font-size: 0.75em;
}

h5 {
  font-size: 0.5em;
  line-height: 1.5em;
  margin-block-start: 0;
  margin-block-end: 0;
}

h6 {
  font-size: 0.35em;
  margin-block-start: 0;
  margin-block-end: 0;
}

br {
  line-height: 0.2em;
}

p {
  display: block;
  margin-block-start: 0;
  margin-block-end: 0;
  margin-inline-start: 0px;
  margin-inline-end: 0px;
}

.Title {
  text-align: center;
  font-size: 3em;
  text-decoration: underline;
}

form {
  margin: 0 auto;
  width: 75%;
  text-align: center;
  font-size: 3em;
}

form#filledForm {
  display: table;
  table-layout: fixed;
  margin: 0 auto;
  width: 100%;
  font-size: 1em;
}

form#filledForm th {
  text-align: left;
}

form#filledForm td {
  width: auto;
  font-size: 0.75em;
  vertical-align: bottom;
}

form#filledForm tr.aligncenter td {
  font-size: 0.75em;
  vertical-align: initial;
}

form#filledForm input[name=relSNonID1] {
  margin-top: 0;
}

form#filledForm input[name=relSNonID2] {
  margin-top: 0;
}

.questionholder {
  display: none;
}

input {
  line-height: 1em;
  font-size: 1em;
  text-align: center;
  width: 100%;
  margin-bottom: 0.5em;
}

input[name=relSNonID1] {
  margin-top: 0.2em;
}

input[name=relSNonID2] {
  margin-top: 0.2em;
}

input[type=radio] {
  margin-bottom: 0;
  visibility: hidden;
}

input[type="radio"]:checked+label {
  border-style: solid;
  padding: 10px;
}

div[data-toggle="buttons"] label.active {
  color: #7AA3CC;
}

div[data-toggle="buttons"] label {
  display: inline-block;
  margin-bottom: 0;
  vertical-align: top;
  cursor: pointer;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}

div[data-toggle="buttons"] label:hover {
  color: #7AA3CC;
}

div[data-toggle="buttons"] label:active,
div[data-toggle="buttons"] label.active {
  -webkit-box-shadow: none;
  box-shadow: none;
}

.text2button {
  border-style: solid;
  padding: 10px;
  cursor: pointer;
}

.multiplechoice {
  line-height: 0.5em;
}

.radio {
  line-height: 2em;
}

.radioChoice {
  font-size: 0.5em;
  cursor: pointer;
}

#result p {
  text-align: center;
  font-size: 2em;
}
<div id="requiredMessage" style="display:none">
  <p>This field is required.</p>
</div>

<form id="TheForm" style="display:block;">
  <div data-toggle="buttons" class="questionholder multiplechoice" id="question13" style="display:block">
    <h5>The world is... </h5>
    <input class="input13" type="radio" id="round" name="isPrevRel" value="round"><label for="round"><p class="radioChoice">round</p></label><br>
    <input class="input13" type="radio" id="square" name="isPrevRel" value="square"><label for="square"><p class="radioChoice">Square</p></label><br>
    <a class="text2button radio" onclick="displayquestion(14)">Next</a>
  </div>
  <div data-toggle="buttons" class="questionholder multiplechoice" id="question14" style="display:none">
    <h5>Do you like snow?</h5>
    <input class="input14" type="radio" id="yes" name="snow" value="yes"><label for="yes"><p class="radioChoice">Yes. If you'd like, explain why</p></label>
    <input class="input14" type="radio" id="no" name="snow" value="no"><label for="no"><p class="radioChoice">No</p></label><br>
    <input name="relSNonID1"><br>
    <a class="text2button radio" onclick="displayquestion(15)">Next</a>
  </div>
</form>
ADyson
  • 57,178
  • 14
  • 51
  • 63
  • you are beautiful. document.querySelector("#question" + b + " input[type=radio]:checked") is precisely what I was looking for. – Sweepster Feb 06 '19 at 23:23