Deconstructing A Dynamic Quiz (Part II)
As mentioned before, the majority of how the quiz is being displayed and ran is written with JavaScript, and with some assistance from jQuery. jQuery is one of many JavaScript libraries, used to help simplify the client-side scripting of HTML.
THE JAVASCRIPT
(function() { /*!!Dynamic Quiz Goes Here*/ })();
Placing the dynamic quiz into an anonymous function creates a private scope which prevents functions outside of this one accessing the variables and methods within it. While not completely necessary, it’s good practice to include.
var questions = [ { question: "What is 2*5?", choices: [2, 5, 10, 15, 20], correctAnswer: 2 }, { question: "What is 3*6?", choices: [3, 6, 9, 12, 18], correctAnswer: 4 }, { question: "What is 8*9?", choices: [72, 99, 108, 134, 156, 199, 232, 444, 567, 681], correctAnswer: 0 }, { question: "What is 1*7?", choices: [4, 5, 6, 7, 8], correctAnswer: 3 }, { question: "What is 8*8?", choices: [20, 30, 40, 50, 64, 77, 99], correctAnswer: 4 } ]; var questionCounter = 0; var selections = [];
Three global variables. The questions variable is a literal notation array to store objects with three properties; the question property houses a string, the choices property houses numbers in an array, and the correctAnswer property stores the number position in the choices array where the correct answer is.
The questionCounter variable is a number to track which question the user is currently on. Setting it to 0 will start the user on the first question (What is 2*5?), while setting it to 2 will start the user on the third question (What is 8*9?).
The selections variable is an empty array, used to collect the user’s choices to the various questions.
function createQuestionElement(currentQuestion) { var qElement = $('<div>', { id: 'question' }); var header = $('<h2>Question ' + (currentQuestion + 1) + ':</h2>'); qElement.append(header); var question = $('<p>').append(questions[currentQuestion].question); qElement.append(question); qElement.append(createRadios(currentQuestion)); return qElement; }
A function is created called ‘createQuestionElement’, and it takes one argument (currentQuestion).
Three variables are created in this function. qElement, with the help of jQuery, writes a div tag with an id of question (<div id='question'></div>). The header variable writes the word “Question”, it then calculates the question number by adding 1 to the currentQuestion argument, and places all this within the number 2 heading tag (<h2>Question #:</h2>). The header variable then gets appended to the qElement variable.
The final variable is created called question. It searches for the question property on the currentQuestion object in the global questions variable, and writes it within a ‘p’ tag. (<p>What is 2*5?</p>). The question variable then gets appended to the qElement variable.
Lastly, a createRadios function (talked about in the next section) on the currentQuestion gets appended to the qElement variable.
qElement and all appended variables and functions get compiled and returned when the creationQuestionElement function is ran. The result looks something like this:
<div id='question'> <h2>Question 1:</h2> <p>What is 2*5?</p> createRadios(currentQuestion) </div>
Note that it won’t display the words ‘createRadios(currentQuestion)’, rather it’ll run the createRadios function.
function createRadios(index) { var radioList = $('<ul>'); for (var i = 0; i < questions[index].choices.length; i++) { var item = $('<li>') var input = '<input type="radio" name="answer" value='+i+' />' input += questions[index].choices[i]; item.append(input); radioList.append(item); } return radioList; }
A new function called createRadios is created with an argument of ‘index’, and is given a variable called radioList to write an unordered list in HTML when called.
A for loop is then created. This for loop reads each of the choices in the question object. It begins at 0, ends at the last item in the choices property on whichever questions object its on, and goes through each choice one at a time. Once it has read all the choices, two new variables are created. The item variable is set to be a list item in HTML. The input variable creates a radio input with the name ‘answer’, and a value related to the number of choices.
The input variable is then set to add and equal the choices in the question object as read by the for loop. Each input value is then appended to the list variable and becomes a list item, and each list item is appended to the radioList variable and becomes apart of a single unordered list.
radioList and all appended variables get compiled and returned when the createRadios function is called. The result looks something like this:
<ul> <input type="radio" name="answer" value='0' /> <li>2</li> <input type="radio" name="answer" value='1' /> <li>5</li> <input type="radio" name="answer" value='2' /> <li>10</li> <input type="radio" name="answer" value='3' /> <li>15</li> <input type="radio" name="answer" value='4' /> <li>20</li> </ul>
function displayNext() { $('#quiz').fadeOut(function() { $('#question').remove(); if(questionCounter < questions.length) { $("#quiz").append(createQuestionElement(questionCounter)).fadeIn(); $('#next').fadeIn(); if(!(isNaN(selections[questionCounter]))) { $('input[value='+selections[questionCounter]+']').prop('checked', true); } if(questionCounter > 0) { $('#prev').fadeIn(); } else { $('#prev').hide(); } } else { $('#quiz').append(displayScore()).fadeIn(); $('#next, #prev').hide(); $('#start').fadeIn(); } }); }
A new function called displayNext is written and will be the main motor for the quiz. When called, it first fades the div with the ID ‘quiz’, once completed, it runs a new function. The purpose of the function is to make sure the quiz fades out first before moving on to the next question. Without the function command, the quiz will jump to the next question, fade out, and then fade back in.
The new function then removes the div with the ID ‘question’, and runs an if / else statement. If the value of questionCounter is less the number of objects in the questions variable, it executes the createQuestionElement function(loading the object based on the current questionCounter number), appends the executed function to the ‘quiz’ div, and fades everything in. It also fades in the button with the ID ‘next’.
In the if statement, it asks if there’s a number in the selection array based on the question the user is on. If there is a number, then the input property with that number value is checked. Basically, if the user made a selection on a question, the quiz remembers their answer should they go back to that previous question.
Another if / else statement is created, asking if the questionCounter is greater than 0. If it is, than it will fade in the button with the ID ‘prev’. If not, it’ll keep that button hidden.
Finally, if the value of questionCounter is greater than the number of objects in the questions variable, then append the displayScore function to the ‘quiz’ div and fade that in along with the button with an ID ‘start’. It’ll hide the ‘next’ and ‘prev’ buttons in this process as well.
Deconstructing the rest of the dynamic quiz continues in Part III