Using textboxes for a quiz

Hi, I would like to get pointed in the right direction to adapt the following code to use textboxes instead of dropdown menus:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
  
       
 
   <title>English</title>
   
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  	<meta name="robots" content="index, follow"/>
   <meta name="description" content=""/>
<meta name="author" content="johnk" />

<meta name="keywords" content=""/>


    
    
    <style>
      ol li {
        background-image: none;
        padding:10px;
      }
    </style>

  </head>
  <body>
    <div id="pagewrap"> 
      <div id="container">
        <div id="content">
           
    
       
	  				

          <h4>For, since or ago?</h4>
          <div class="scroll">
            <form method="post" id="myForm" name="f">
              <ol>
                <li>
               It's been raining 
                  <select name="question1">
                    <option value="na">&nbsp;</option>
                    <option value="a"> for </option>   
                    <option value="b"> since </option>
                      <option value="c"> ago </option>  
                  </select> 
                 2 hours.
                </li>
                <li>
                  They have lived here
                  <select name="question2">
                   <option value="na">&nbsp;</option>
                    <option value="a"> for </option>   
                    <option value="b"> since </option>
                      <option value="c"> ago </option>  
                  </select>
                 1990.
                </li>
                
              </ol>
            
             <input type="submit" id="submit" value="Result" />
              <input type="reset" class="reset" id="reset" name="reset" value="Start again" />
            </form>
             <div id="score"></div> 
               <div class="address">
           
            </div>
          </div> 
        </div> 
      </div> 
    </div>
    
    <script>
      Object.size = function(obj) {
        var size = 0, key;
        for (key in obj) {
          if (obj.hasOwnProperty(key)) size++;
        }
        return size;
      };
      
      (function(){
        "use strict";
        window.checkAnswers = function(opts){
          
          function validateInput(){
            var question,
                answer;
                
            for (question in opts) {
              if(opts.hasOwnProperty(question)) {
                answer = f.elements[question].options[f.elements[question].selectedIndex].value;
                if(answer === "na"){
                  opts[question].state = "not-filled-in";
                } else if(answer === opts[question].answer){
                  opts[question].state = "correct";
                } else {
                  opts[question].state = "error";
                }
              }
            }
          }
          
          function markCorrectOrIncorrect(){
            var question, 
                li;
            
            for (question in opts) {
              if(opts.hasOwnProperty(question)) {
                var img = new Image(),
                li = f.elements[question].parentElement,
                feedbackImg = li.getElementsByTagName('img')[0];

                if (feedbackImg){
                  li.removeChild(feedbackImg);
                }
                
                if(opts[question].state === "correct"){
                  img.src = "http://www.littletherese.com/tick.jpg";
                  li.appendChild(img)
                } else if(opts[question].state === "error"){
                  img.src = "http://www.littletherese.com/x.jpg";
                  li.appendChild(img)
                }
              }
            }
          }
          
          function displayScore(){
            var correct = 0,
                error = 0,
                score = document.getElementById("score"),
                totalQuestions = Object.size(opts),
                question;

            for (question in opts) {
              if(opts.hasOwnProperty(question)) {
                if(opts[question].state === "correct"){
                  correct ++
                } else if(opts[question].state === "error"){
                  error ++
                }
              }
            }
            score.innerHTML = "You got " + correct + " out of " + totalQuestions;
          }
          
          function init(){
            validateInput();
            markCorrectOrIncorrect();
            displayScore();
          }
          
          init();
        }
      }());

      f.onsubmit = function(){
        checkAnswers({
          question1: {answer: "a"},
          question2: {answer: "b"},
       
        })
        return false;
      }
      
    f.reset.onclick = function(){
  var imgs = document.querySelectorAll('img');
  for(var i=0; i<imgs.length; i++){
    imgs[i].parentNode.removeChild(imgs[i]);
  }

  document.getElementById("score").innerHTML = "";
}
      
    </script> 
  </body>
</html>

Thanks for any help

I was thinking of javascript that allowed for more than one correct answer to the quiz questions, like in this snippet:


if(answer1 == 'an acceptable answer || answer1 == 'another acceptable answer') {
 //here I'd like to say something like: img.src = "http://www.littletherese.com/tick.jpg"
     }

The above image refers to a “correct tick” after the question.

Hi,

Sorry it took a while to answer, but I was proper busy.

Anyway, the first thing we need to do is make a form with checkboxes and sample questions.
Can you do that?

Also, are you using jQuery (I seem to remember seeing it in your other page).
It’s not strictly necessary, but will simplify the code somewhat.

Ok, no problem. Actually I was thinking of textboxes. I suppose the HTML for each question should be something like:

 
<ol>
<li>He 
<input id="question1" name="question"  type="text" /> like football. 

// other questions here  
</li> </ol>




And I assume the javascript should include something like:


var answer1 = document.getElementById('question1');
if(question1 == 'does not || a1 == 'doesn't') {

"http://www.littletherese.com/tick.jpg", // here I'd like to have the "correct tick"
}

? Yes, I use the jQuery library in other scripts

Ok, but from a linguistic perspective, are you sure this is a good format?

For example, what about capitalization “Doesn’t”?
Or what if people are copy pasting out of Word and get their apostrophes mixed up.
“doesn’t” is not the same as “doesn’t”

My idea is that in some cases more than one answer can be considered correct. For example:

He isn’t = He is not. Or, does not = doesn’t, so I wanted to include the “or” symbol for that reason.

Well I would use capitals only when appropriate, for example “Does” at the beginning of a sentence. But I don’t see the difference between

“doesn’t” is not the same as “doesn’t”
??

Oh…is it a different apostrophe mark? Not easy to see…or maybe I need better glasses! Maybe in this case, add another “or” symbol with the other apostrophe? As in:


var answer1 = document.getElementById('question1');
if(answer1 == 'does not || answer1 == 'doesn't'  || answer1 == 'doesnt' ) {

"http://www.littletherese.com/tick.jpg", // here I'd like to have the "correct tick"
}

But I couldn’t find the strange ’ on my keyboard ;o(

Ok, well which answers you choose to accept is up to you.

Here’s how you might go about this using inputs:

<form>
    <ol>
        <li>He <input id="q1" type="text" /> like football.</li>
        <li>He <input id="q2" type="text" /> got any money.</li>
    </ol>
    <input type="submit" id="submit" value="Result" />
</form>
var answers = {
    "q1": ["doesn't", "does not"],
    "q2": ["hasn't", "has not"]
};

function markAnswers(){
    $("input[type='text']").each(function(){
        if($.inArray(this.value, answers[this.id]) === -1){
            $(this).parent().append("<img src='http://www.littletherese.com/x.jpg' />");
        } else {
            $(this).parent().append("<img src='http://www.littletherese.com/tick.jpg' />");
        }
    })
}
    
$("form").on("submit", function(e){
    e.preventDefault();
    markAnswers();
});

Here’s a demo

Try and use some of the bits from the other scripts we worked on to add in the other functionality (reset button etc).

Let me know if you get stuck.

Ok, I’ll chew on that and report back. Thanks!

I’m with Pullo on this. I think that the reason the drop down was used in the original script was to limit responses to a known set. This is typical multiple choice questioning. The drop down has the advantage of displaying all answers on the same line. If you adopt an alternative strategy - say radio buttons, you need to show all alternative answers and pick the correct one by clicking the button - possibly a multi-line approach…

Your idea of using a text box does not avoid displaying the alternatives and expects the user to type in a response, which may not match the choices you offer. For instance if your choices were “red” and “blue” and the user typed “yellow” or “blu” how would you check these against the correct answer?

I personally prefer the drop down approach. :slight_smile:

Exactly.
My students (I sometimes work as an English trainer) can be incredibly inventive, and in such a scenario validation of the answers can quickly turn into a nightmare.

I agree with you both halfheartedly. Indeed if it were up to me, I would probably just use dropdown menus or radio buttons (multiple choice questions) for even the most advanced English exams, like Cambridge Proficiency etc. Instead, what some of these exam questions are testing is the imagination / creativity of the students, many of whom, even in their own language, would be incapable of “inventing” stories for compositions etc. So, yes, I think multiple choice is a foolproof way of testing language skills, even for listening exercises, though with the obvious exception of speaking skills.
My idea is to include a few “ors” (maybe 3 or 4, depending on the question) in the javascript to allow for a variety of correct answers, although I wouldn’t consider something like “blu” to be a valid substitute for “blue”. There’s also the element of students improving their spelling skills I suppose. But I would probably only use textboxes in a minority of questions, like for eg. “I (be)________very tired yesterday, so I (go) _______ to bed early.” And also because it’s hard to think of 3 or 4 different answers in a dropdown menu for such basic questions as these.

I got the reset button working, but haven’t managed to get the “you got 1 out of 2” correct, And also the “X” incorrect image shows when pressing submit without having answered any questions. Here’s the code:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
  
  


        
 
   <title>English </title>
   

    
    
    <style>
      ol li {
        background-image: none;
        padding:10px;
      }
    </style>

  </head>

  <body>
    <div id="pagewrap"> 
      <div id="container">
        <div id="content">
        
             
         
          <div class="scroll">
            <form>
            
    <ol>
        <li>He <input id="q1" type="text" /> like football.</li>  
        <li>He <input id="q2" type="text" /> got any money.</li>
    </ol>               
        <input type="submit" id="submit" value="Result" />
     <input type="reset" class="reset" id="reset" name="reset" value="Start again" /> 
    
</form>

       <div id="score"></div>  
          
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script>
     /*global $:false */
  function clearAnswerImages(){
        $("img").remove();
}
      

  function markAnswers(){
    $("input[type='text']").each(function(){
        if($.inArray(this.value, answers[this.id]) === -1){
            $(this).parent().append("<img src='http://www.littletherese.com/x.jpg' />");
        } else {
            $(this).parent().append("<img src='http://www.littletherese.com/tick.jpg' />");
        }
    });
}
      function displayScore(){
        var numQuestions = $(".question").length,
            questionsCorrect = $("img.correct").length;

     $("#score").html("You got " + questionsCorrect + " out of " + numQuestions);
      }

      $("form").on("submit", function(e){
        e.preventDefault();
        clearAnswerImages(); 

   
       var $questions = $(".question");
        $questions.each(function(){
          var answer = $(this).find("input:checked"),
              key = answer.attr("name"),
              val = answer.attr("value");

          if(answer.length === 0){ 
            mark($(this).find("p"), "unanswered");
          } else if (answers[key] !== val){
            mark(answer.parent(), "incorrect");   // I  changed this line
          } else {
            mark(answer.parent(), "correct");
          } 
        });

        displayScore();
      });


  $("input[type=reset]").on("click", function(){
  $("input:checked").prop("checked", false);
  $('#score').empty(); //I inserted this line      
  clearAnswerImages(); 
});
$("form").on("submit", function(e){
    e.preventDefault();
    markAnswers();
});

       var answers = { 
        "q1": ["doesn't",  "does not"],
        "q2": ["hasn't",  "has not"]
       
                                                
      }; 
    </script>
  </body>
</html>

  

By the way, I haven’t been able to find the html code for this strange single quote mark (´ ). I mean, to use it as in “doesn´t” (as another accepted answer). Thanks.

I have modified your code to give you the answer you were seeking. I have removed several chunks that were not used - they were left over from the version using the drop-down boxes.

This version has the value of the input boxes preset ( value=“doesn’t” and value=“hasn’t”) to allow you to experiment without all the typing. You might like to delete these values before you release it to a wider audience.

If you click on “Result” you will see the images and the scores. Try deleting or changing the contents of the boxes to get different results. You can do this without reloading the page as each click of “Result” clears all previous information.

I have also set up preloading of the images to make sure they are available when needed. If you don’t do this there is a delay in displaying the tick or the cross. :slight_smile:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">
</script>
<style type="text/css">
 body { font-family:arial, helvetica, sans-serif; font-weight:bold; font-size:16px; color:#000; text-align:left; margin:3px 0px; }
 input { font-size:16px; }
 #pagewrap  { width:500px; height:500px; margin-left:20px;  }
 #score { margin-top:10px; }
 ol li { padding:10px; }
</style>
</head>

<body>

<div id="pagewrap">
<p>Type or delete in the text boxes below</p>
  <form>
    <ol>
      <li>He <input id="q1" type="text" size="20" value="doesn't"> like football.</li>
      <li>He <input id="q2" type="text" size="20" value="hasn't"> got any money.</li>
    </ol>
    <input type="submit" id="submit" value="Result">
    <input type="reset" class="reset" id="reset" name="reset" value="Start again">
  </form>
  <div id="score">
    <!-- writes to here -->
  </div>
</div>
<!-- end pagewrap -->
<script type="text/javascript">
 A= new Array();   // preload images
 A[0]=new Image(28,15); A[0].src="http://www.littletherese.com/tick.jpg";
 A[1]=new Image(22,15); A[1].src="http://www.littletherese.com/x.jpg";
//
$("form").on("submit", function(e){ e.preventDefault(); $("img").remove(); markAnswers(); });
// -----
$("input[type=reset]").on("click", function(){ $("img").remove(); $("#score").html(""); });
// ------
var answers = {"q1":["doesn't","does not"], "q2":["hasn't","has not"] }
var numQuestions=0, questionsCorrect=0;
//
  function markAnswers()
    { $("input[type='text']").each( function(){
           // add one to questions counter on each pass
             numQuestions++;
             if($.inArray(this.value, answers[this.id]) == -1)
                  { $(this).parent().append('<img src="'+A[1].src+'">'); }
             else { $(this).parent().append('<img src="'+A[0].src+'">');
                   // add one to correct answer counter on each pass
                    questionsCorrect++; }
            // display scores
             $("#score").html("You got " + questionsCorrect + " out of " + numQuestions);
        } );
   // reset counters after marking is complete
      numQuestions=0; questionsCorrect=0;
   }
//
</script>
</div>

</body>

</html>

Sorry, been a bit busy. That code works great! Thanks AllanP!