2

The answers given to a similar question:How to use the "required" attribute with a "radio" input field don't seem to work in this case. I am adapting a multiple choice quiz provided via radio buttons.The quiz has radio buttons built into an external js file.

How it works

The quiz is a sort of personality test, by answering the twenty questions (4 sets of 5 questions each) you get points (there are no correct answers). The sets following the first appear by clicking the "Submit Answer" button.

The points are divided into 3 bands: 0 to 22, 23 to 43, 44 to 65. Each of which is accompanied by an explanation and an image.

The script works fine, only the problem remains that the radio buttons do not have the "required" attribute. So if one clicks without selecting an answer, he still gets a score of 0.

I have tried several times make the radio button mandatory, as in this example : https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_radio_required

The HTML page look like this:

HTML

<p id="test_status"></p>

<div id="box">
<p id="test"></p>
<p id = "after"></p>
<p id = "message"></p>
<p><img id = "picture"></p>
</div>

nothing more.

Script

 / setup initial vars

    var pos = 0;
    var score_all = 0;
      var score = 0;
    var test, test_status, question, choice, choices, chA, chB, chC, chD, chE;
    var l_messagge = "";
    var picture = "";
    var tipo = "";

    // this is a multidimensional array with 4 inner array elements with 5 elements inside them
    var questions = [
      {
          question: "question1",
          a: "answer1",
          b: "answer2",
          c: "answer3",
          d: "answer4",
          e: "answer5",
      score_a: 1,
      score_b: 4,
          score_c: 3,
          score_d: 2,
      score_e: 0
                },
// three more questions follow.

];

    // create the get function

     function get(x){
        return document.getElementById(x);
    }

        // this function renders a question for display on the page
    function renderQuestion(){
    test = get("test");

    //test.innerHTML = questions.length;
      if(pos >= questions.length){
    opis();
    document.getElementById("after").style.visibility = "visible";
     //   get("test_status").innerHTML = "Test completed";
        get("test_status").innerHTML = score_all;
        test.innerHTML = "<h2> "+l_messagge+"</h2>";
        document.getElementById("message").innerHTML = tipo;
    document.getElementById("picture").src = picture;
    
       // resets the variable to allow users to restart the test
        pos = 0;
        score_all= 0;
        // stops rest of render Question function running when test is completed
        return false;
      }
      get("test_status").innerHTML = "Question "+(pos+1)+" of "+questions.length;
              get("test_status").innerHTML = score_all;
      question = questions[pos].question;
      chA = questions[pos].a;
      chB = questions[pos].b;
      chC = questions[pos].c;
      chD = questions[pos].d;
      chE = questions[pos].e;
      // display the question
      test.innerHTML = "<h3>"+question+"</h3>";
      
    // display the answer options
    // the += appends to the data we started on the line above
test.innerHTML += "<label> <input type='radio'  name='choices' value='A'> "+chA+"</label><br>";
      test.innerHTML += "<label> <input type='radio' name='choices' value='B' "+chB+"</label><br>";
      test.innerHTML += "<label> <input type='radio' name='choices' value='C'> "+chC+"</label><br><br>";
      test.innerHTML += "<label> <input type='radio' name='choices' value='D'> "+chD+"</label><br>";
      test.innerHTML += "<label> <input type='radio' name='choices' value='E'> "+chE+"</label><br><br>";
      test.innerHTML += "<button onclick='checkAnswer()'>Submit Answer</button>";
    }
         
// Create a function to check the answers
            function checkAnswer(){
      // use getElementsByName because we have an array which it will loop through
      choices = document.getElementsByName("choices");
      for(var i=0; i<choices.length; i++){
        if(choices[i].checked){
          choice = choices[i].value;   // będzie 'A', 'B' lub 'C'
      if (choice == 'A' ) {score = questions[pos].score_a;}
      else if (choice == 'B' ) {score = questions[pos].score_b;}
      else if (choice == 'C' ) {score = questions[pos].score_c;}
      else if (choice == 'D' ) {score = questions[pos].score_d;}
        else
        {score = questions[pos].score_e;};
        }
      }
      // checks if answer matches the correct choice
      
        score_all = score_all + score;
      
      // changes position of which character user is on
      pos++;
      // then the renderQuestion function runs again to go to next question
      renderQuestion();
    }
  
  function opis(){
     if (score_all >=  0 && score_all < 4) {
         picture = "img/not.jpg";
         l_messagge = "Message1";
         tipo = "Tipo1";
      }
        else if (score_all >=  4 && score_all < 7  ) {
          picture = "img/gorg.jpg";
          l_messagge = "Tipo2,";  
      }
        else if (score_all >=  7 && score_all < 10  ) {
          picture = "img/blip.jpg";
          l_messagge = "Tipo3";  
      }
        else if (score_all >=  10 && score_all < 13  ) {
          picture = "img/plap.jpg";
          l_messagge = "Tipo4";  
      }
      else
      {
         picture = "img/tik.jpg";
         l_messagge = "message5" ;
      }
    return;
  }
        // Add event listener to call renderQuestion on page load event
    window.addEventListener("load", renderQuestion);

but without results.

The question received a response:

var myStuff = `
<label> <input type='radio' id='oRadA' name='choices' value='A' required='required'> ${chA}</label><br>
<label> <input type='radio' id='oRadB' name='choices' value='B'> ${chB}</label><br>
<label> <input type='radio' id='oRadC' name='choices' value='C'> ${chC}</label><br>
<label> <input type='radio' id='oRadD' name='choices' value='D'> ${chD}</label><br>
<label> <input type='radio' id='oRadE' name='choices' value='E'> ${chE}</label><br>
`;
test.innerHTML = myStuff;

but I am unable to make it work.When I transcribed it, the radio buttons and the answers disappeared, only the questions remain visible..

Another solution could be to insert the radio buttons directly into the html page, but I should also transfer the related javascrip part, which I don't know how to do.

As you can see I know very little about Javascript, could someone please help me? Thanks for the attention.

Meimei
  • 165
  • 6
  • Sorry, due to extreme busy-ness the last few days I haven't had time for SO, so I've put a bounty on this question to draw the attention of other members to assist. I hope that this helps and that the answers are not too late. Remember that the tags are intended to draw the attention of members skilled in that (tag) area. Also, you should probably post a sample of your HTML structure, as well as a clear explanation of how one question is intended to function (i.e. how is each part of a `question` object used?) Best wishes! – cssyphus Aug 07 '20 at 13:45
  • Thanks @cssyphus, I add HTML code and a few words of explanation on how the quiz works, I will give you back the bond points. – Meimei Aug 07 '20 at 18:09
  • Hi Meimei, first of all, it is not possible to cancel a bounty - the points must be awarded to someone other than me. Secondly, if **you** solved it - with or without assistance - **you** are worthy of the reward. Please add a new answer below and move your solution (added to bottom of your question) into that answer, and I will award the bounty. I don't have a choice - I must award the bounty to someone - and it would be a pleasure to award it to you *(or, to your wife if she has a StackOverflow account)*. A problem solved is a problem solved, and the solver is worthy of the award. – cssyphus Aug 09 '20 at 14:00
  • To answer another question within your question, there are two ways to add javascript code to an HTML page. The first, as you know, is with an external `.js` file, inserted via a `` tag *(usually in the `` of the document)*. The second is almost the same: you add another script tag into the document body *(usually, just above the closing `

    ` tag)* with the javascript BETWEEN the script tags, like this: `. You can have as many script tags as you want on your page.

    – cssyphus Aug 09 '20 at 14:13

2 Answers2

2

Remember that two elements cannot have the same ID (bad things happen). You might not need the ID attributes (I don't know what's in the rest of your js) - anyway the form doesn't need them (forms only use the name= and value= elements).

You should only need ONE of the required attribute tags (the others won't hurt but are not needed) - but sometimes I have needed to write required="required" rather than just required.

Finally, I used modern JS template literals to make the code a little easier to read/modify.

Please let me know if this doesn't solve your problem and we'll keep troubleshooting.

var myStuff = `
<label> <input type='radio' id='oRadA' name='choices' value='A' required='required'> ${chA}</label><br>
<label> <input type='radio' id='oRadB' name='choices' value='B'> ${chB}</label><br>
<label> <input type='radio' id='oRadC' name='choices' value='C'> ${chC}</label><br>
<label> <input type='radio' id='oRadD' name='choices' value='D'> ${chD}</label><br>
<label> <input type='radio' id='oRadE' name='choices' value='E'> ${chE}</label><br>
`;
test.innerHTML = myStuff;
cssyphus
  • 37,875
  • 18
  • 96
  • 111
  • Hi @cssyphus, I added the missing pieces of code. Thanks for your precious help. – Meimei Aug 03 '20 at 18:31
  • My fault, it doesn't work. I replaced "var myStuff =" with "var test, test_status, question, choice, choices, chA, chB, chC, chD, chE; and "test.innerHTML = myStuff;" with "test.innerHTML += "";" the questions disappear. Clicking 'submit' several times, score is "0". Which is correct. Maybe I should buy the book you suggested, I hope to understand it. – Meimei Aug 04 '20 at 12:06
  • I edited question, I added all the code (apart from the radio buttons). I replaced "var myStuff =" with "var test, test_status, question, choice, choices, chA, chB, chC, chD, chE; and" test.innerHTML = myStuff; "with" test.innerHTML + = " ";" the questions disappear. Where am I wrong? – Meimei Aug 05 '20 at 07:42
  • I found a solution, if you could check it out it would be better. I wait for you to cancel the bounty to auto-answer my question. Thanks. – Meimei Aug 08 '20 at 12:10
  • Thanks for everything, I posted my solution.As for JS in HTML, I meant that I don't know how to "carry" the js snippet into radio buttons already inserted in an HTML page. Because I've been using Twine for 6 months, I know a little about some ES6 syntax (I thought they were Twine native). – Meimei Aug 10 '20 at 07:52
  • 1
    Do you mean `Event Delegation`, as described [here](https://learn.jquery.com/events/event-delegation/)? This covers the case where javascript cannot detect/trap user events made on elements that were added to the DOM **after** initial page load. Event Delegation allows you to put an event handler on a parent element that ***does*** exist at page load, and when the future children are eventually added to the DOM, the user events on those new children can be detected *when they bubble up to that parent element*. Extremely useful, especially with ajax. – cssyphus Aug 10 '20 at 14:30
  • Sorry for my poor english, i meant when the radio buttons are not dynamically created (when them are embed in html), like this: Male
    Female
    Neutral
    – Meimei Aug 11 '20 at 08:33
  • 1
    Are you asking about how to dynamically create radio buttons based on what the next question is? If so, the usual approach is to have generic **values** (value="a", b, c, etc) and only replace the answer string, via a loop (also determines how many radio buttons are created). To insert into the HTML page, create the radio buttons *as a string* (all of them, including labels, text, `` tags, `` tags etc, the entire bit of html you want to inject onto the page) - as a ***string assigned to a var*** (e.g. `VarName`). Then just `document.getElementById('bob').innerHtml = varName` *Voila!* – cssyphus Aug 11 '20 at 12:35
  • Sorry @cssyphus my bad english. I asked the contrary. I like have RBs. and questions already in html page, as in Shahnavaz reply:
    Male
    Female
    Neutral
    , and inject into the js. I have this problem too some answers are too long: RB. answer "Think,"It's too late I have go to wok", them back to sleep". This create a gap between RBs. that are no longer aligned well. How solve this? Thanks.
    – Meimei Aug 13 '20 at 12:54
  • Hi Meimei, sorry but you will need to ask this as a different question. Then post a reply to any of my comments with a link to the new question. Please explain carefully, so that it is clear what the end result should look like. *Thanks!* – cssyphus Aug 14 '20 at 12:58
0

The problem

I solved the problem of making mandatory to select one of the answers to the test questions, with the help of my wife, using what I would call an example of Lateral Thinking.

that is to say, by not operating on the mandatory nature of the selection but on the effects of its lack. In few words: If you don't select an answer you don't go ahead and you don't need any "required".

How

I set the initial score value to 10 (score not reachable on the first question or later) which operates as a block.

 score = 10;

if the user selects the first answer the maximum value he can reach is 4 and goes to the next question. For each question the user has "score = 10", and must lower it by clicking on an answer.

if (score <10) {
score_all = score_all + score;
else {// rendering error message
get ("message"). innerHTML = "<i>" + "Please select your answer." + "</i>";
  }
}

The selected answers are summed in:

score_all = score_all + score;
Meimei
  • 165
  • 6