JS promises for online quiz

Hi, I would like to use js promises to make online multiple choice type questions. I was trying to figure out how I could integrate some elseif statements

in the following code, in order to add more options:


<script type="text/javascript">
      var validationConfig = {
        '.question_1': {
          checks: 'a',
          field: 'Question 1'
        },
				'.question_2': {
          checks: 'c',
          field: 'Question 2'
        }
      };

      function showAlerts(errors) {
        var alertContainer = $('.alert');
        $('.error').remove();

        if (!errors) {
          alertContainer.html('<small class="label success">All correct</small>');
        }
        else {
          $.each(errors, function (idx, err) {
            var msg = $('<small></small>')
                .addClass('error')
                .text(err.error);

            err.control.parent().append(msg);
          });
        }
      }

Any help appreciated.

Hi,

So, let’s take a few steps back, as the promises solution was something I posted in a previous thread and might or might not be the best solution for you.

As I understand it, you have a page full of multiple choice questions, which when the user submits the form, you are validating server-side using PHP.

You are now considering using JS to add an additional layer of validation on the client-side.

Is that correct?

I was just thinking that the javascript solution would have a more responsive feel to it than php - for the user I mean,
even though now the php code is also doing the job, thanks to help from the php forum…

Yea, I think the client side validation seems better. I was wondering if it might be possible to adapt your promises code
with the usual js if and elseif statements, but I couldn’t find a way to do it.

I also thought that javascript may be more “lightweight”
than php, since it doesn’t depend on round trips to the server for validation? Thanks.

This is a php page I have been working on. I think it does everything I need in php.

Hi there,

I’ve taken that page as a base and have added the JS functionality we discussed.

Here’s a demo.

Please not: the JS is only half finished (although the page works already).

Have a look at the source code and tell me if you think that is something you could work with.
If it is, I’ll rework the JavaScript and write a more verbose post about what I have done and how you can extend things.

Hope that helps some.

I’ve just been thinking about this
If you don’t want the answers to be visible, then perhaps AJAX would be the way to go.
This way, you would use JavaScript to submit the form data to a PHP script, which would then evaluate them.
This would also improve the feel of the page (i.e. no refresh), but not show the answers in the source code.

Well, the demo page looks very good to me, and I think I can adapt it for my needs. Just wondering how I can activate the php code, for people with js turned off? The answers being visible in the source code would be ok, although if the Ajax method isn’t too complicated, that would be a good idea too. Thanks.

Hi,

Excellent :slight_smile:

It works like this:
A visitor with JS turned on fills out the form and clicks submit.
The JS catches the submit event, prevents the form from submitting, validates the user’s input, then gives the user feedback.
No page reload takes place.

Then a visitor with JS turned off fills out the form and clicks submit.
The form submits to your PHP script and is validated there.
The PHP script reloads the page or redirects to another page.

Then it’s better to use the solution we have here.
AJAX would further complicate things.

What I’ll do is rework the JS in the next couple of days and post back here.

Great! So, do you mean that I should have the php code in the same page as the js? No need to add any if statements to distinguish between js and php?

Nope, this is not possible.
You should have:

A HTML page containing the form.
A CSS file which contains the styles for your page.
A JS file which contains the code to validate user input on the client-side.
A PHP file which contains the code to validate user input on the server-side (in case a user has JavaScript disabled).

Ok, the css file is understood. But do you mean something like this in the html file?


<form action="for_to.php" method="post" id="form_id" name="f"> 

Exactly. You specify where to send the form data in the form’s action attribute.
for_to.php is a remote file which must be interpreted before it is served to the browser.

The JS file on the other hand is included in the page like so:
<script type=“text/javascript” src=“…”></script>
In contrast to the PHP file, it is interpreted at run time and can thus do things like manipulate form data.

Ok, so you mean the javascript that’s used to configure the dropdown boxes, etc should be included near the end of the HTML page?
But do I also need to link to these files in my HTML page?


<script src="jquery.js" type="text/javascript"></script>
<script src="validator.js" type="text/javascript"></script>

Nope.
Are they from my old demo?

This one s hould work as is.

Yea, they’re from your old demo. But just to clarifY: so I just add the js code to my html file, and therefore I don’t need a separate js file (linked to
from my html page)?

Oh right, yeah, sorry.
You can either stick the JS in an external file, or include it directly in the page.
I’ll sort out the demo for you tomorrow and explain what I have done.

ok thanks, but I think you deserve a weekend break! There’s no hurry ;o)

Hi,

I’ve tidied up the code somewhat:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Clases particulares de ingl&eacute;s con profesor nativo en Granollers... </title>
    <link rel='stylesheet' type='text/css' href='http://www.littletherese.com/say_tell.css' />
    <style>
      ol li {
        background-image: none;
        padding:10px;
      }
    </style>
  </head>

  <body>
    <div id="pagewrap"> 
      <div id="container">
        <div id="content">
          <h4>For or to?</h4>
          <div class="scroll">
            <form action="" method="post" id="myForm" name="f">
              <ol>
                <li>
                  She had to go to the shop
                  <select name="question1">
                    <option value="na"></option>
                    <option value="a"> for </option>   
                    <option value="b"> to </option> 
                  </select> 
                  buy bread.
                </li>
                <li>
                  They went to Italy
                  <select name="question2">
                    <option value="na"></option>
                    <option value="a"> to </option> 
                    <option value="b"> for </option> 
                  </select>
                  see a football match.
                </li>
                <li>
                  She had to study a lot
                  <select name="question3">
                    <option value="na"></option>
                    <option value="a"> for </option>   
                    <option value="b"> to </option> 
                  </select> 
                  pass the exam.
                </li>
                <li>
                  You have to pay
                  <select name="question4">
                    <option value="na"></option>
                    <option value="a"> for </option>   
                    <option value="b"> to </option> 
                  </select> 
                  get a license.
                </li>
                <li>
                  She needed lots of money
                  <select name="question5">
                    <option value="na"></option>
                    <option value="a"> to </option>   
                    <option value="b"> for </option> 
                  </select> 
                  buy the house.
                </li>
                <li>
                  I asked my friend 
                  <select name="question6">
                    <option value="na"></option>
                    <option value="a"> to </option>   
                    <option value="b"> for </option> 
                  </select> 
                  some money. 
                </li>
                <li>
                  Some people need glasses
                  <select name="question7">
                    <option value="na"></option>
                    <option value="a"> to </option>   
                    <option value="b"> for </option> 
                  </select> 
                  reading. 
                </li>
                <li>
                  I didn't have time
                  <select name="question8">
                    <option value="na"></option>
                    <option value="a"> for </option>   
                    <option value="b"> to </option> 
                  </select> 
                  repair the car. 
                </li>
                <li>
                  I have been working here
                  <select name="question9">
                    <option value="na"></option>
                    <option value="a"> since </option>   
                    <option value="b"> for </option> 
                  </select> 
                  10 years. 
                </li>
                <li>
                  Fresh fruit is good
                  <select name="question10">
                    <option value="na"></option>
                    <option value="a"> for </option>   
                    <option value="b"> to </option> 
                  </select> 
                  your health.
                </li>
              </ol>
            
              <div id="score"></div> 
              
              <input type="submit" id="submit" value="Result" />
              <input type="reset" class="reset" id="reset" name="reset" value="Start again" />
            </form>
          </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: "a"},
          question3: {answer: "a"},
          question4: {answer: "a"},
          question5: {answer: "a"},
          question6: {answer: "a"},
          question7: {answer: "a"},
          question8: {answer: "a"},
          question9: {answer: "a"},
          question10: {answer: "a"}
        })
        return false;
      }
      
      f.reset.onclick = function(){
        location.reload();
      }
    </script> 
  </body>
</html>

This will work as a standalone example. You don’t need any other libraries.
I tested in the latest version of Chrome, Opera, FireFox, Safari (Win), as well as IE 7 - 10.

If you add more questions, just modify the opts object passed to checkAnswers()
The format is:

select element name, {answer: "option value of correct answer"}

Please also note that it is better to use a <ol> (ordered list) to structure your questions.

Hope that helps.