Breaking

Sunday, November 17, 2019

JavaScript Quiz Application - learn web development with Android

Today's walkthrough is a complete guide to creating a quiz application. What we will be doing here is to expand on our gained knowledge of object and arrays, already established in our JavaScript tutorials. We will use this knowledge of object and arrays to populate questions from our JavaScript. I assume you must have gone through that article but if you haven't, don't worry, we will try to bring you up to speed with what is going on in here. Let's get started already.

We start with the markup and as you can see from the preview below, we need 5 major containers.

Image
  • The title container.
  • The Question container.
  • The options container and
  • The Next Button container.

These are all embedded in the quiz container. We also need a result container which is going to be hidden up to a time when the quiz is completed.


<div id="quizContainer">
<div id="title">Research Quiz</div>
<div id="question"></div>
<div class="options" >
<label><input type="radio" name="opt" value="A" ><span id="option1" ></span></label>
<label><input type="radio" name="opt" value="B" ><span id="option2" ></span></label>
<label><input type="radio" name="opt" value="C" ><span id="option3" ></span></label>
<label><input type="radio" name="opt" value="D" ><span id="option4" ></span></label>
</div>
<button id="nextbutton" onclick="nextButton()">Next Question</button>
</div>
<div id="result" >
<div id="resultscore" ></div>
<a id="retry" href="file:///storage/0000-0000/quiz.html" >Retry</a>
</div>

Let's talk a bit on the options container, we need our option to have selectors and for this we use the input element to insert the radio-button, as we set its type to radio. We also include a span element which is going to hold our options answer. All this are placed inside a label which carries the full width of an option container.

Note that, the input are given the same name; the reason being that you can only choose one option of the four. The span elements which is going to hold the option values is given an id attribute, these id attributes are later going to be populated with answers from JavaScript.

The "Next Button" container is clear to understand, it's onclick attribute is to call a function (nextButton()) from JavaScript which is going to next our questions and options.

Up next is the result container, although we are not going to have it displayed at the moment. The result container contains two element the resultscore container and the retry button. We'll populate our score from Js and place it in the resultscore container while the link will be used to refresh our page back to the start of the question.

Let's go style all of this so we have an actual interface. I like to get rid of browser's default setting at first, to do that we assign asterisk a margin, border and padding of 0pixels.


*{
margin:0px;
border:0px;
padding:0px;
}
We also set the body's background color to white since I need a clean interface.

body {
background-color:white;
}
Okay let's begin to style our containers and we start with our quiz container.

#quizContainer{ }

And inside of the curly braces, let's add a few styling, we assign it a width and height of 1000pixels, also add to it a black and white color combo, inclined at an angle of 20degrees for a background color. We move it 200pixels away from the top, just so it centers rightly in the page.


width:1000px;
height:1000px;
background:linear-gradient(20deg, black, white, black);
margin-top:200px;
}

The next thing we want to style is the title container, we'll make it's font size large enough to be visible by setting it to 100px, that's relatively large, we can even go ahead to bold it by setting it font weight to bolder. We also want it's text to be centrally aligned, we set its text-align to center, add a white text color and play around with the text shadow property.


#title{
font-size:100px;
font-weight:bolder;
text-align:center;
color:white;
text-shadow:5px 5px 10px black, 5px 10px 25px blue;
}

Let's get to the questions container.


#question{
}

We give it a width of 950px and height of 200px, we use the margin top and left property to correctly align it inside the quiz container.


width:950px;
height:200px;
margin-top:100px;
margin-left:25px;

We also go ahead to add a background-color, this is going to be 3 nice color merge of sky blue, pearl night blue and traffic blue all inclined to 10degrees to suitably give us what we want.


background:linear-gradient(10deg, rgb(6,104,178),#031060,rgb(4,6,123));

We can then add border-radius to have our question container edges rounded and also a squirrel grey border color.


border-radius:20px;
border: 2px solid rgb(107,125,142);

We can also add a shadow to the container.


box-shadow:10px 10px 15px black;

We just added a 10px horizontal, 10px vertical and 15px blurred black shadow to the container. We also want our questions text to be centrally aligned, have a font size that's not too small, we can set that to 45px and also have a white text color.


text-align:center;
font-size:45px;
color:white;

And that is all for the question container, let's get to the options container, we'll start with styling the label.


label {
}

Remember that the label is to carry the total width of an option, we desire to have two options in a row, so we can have it display inline-block to also grasp the width and height value.


display: inline-block;
width: 470px;
height:100px;

We're going to be using the same background-color as that of the question container, we can also add margin top and left property to have these labels equally spaced and have a relatively distance from the question container.


background:linear-gradient(10deg, rgb(6,104,178),#031060,rgb(4,6,123));
margin-left:20px;
margin-top:32px

We also add a border, border-radius and the box shadow property, just as we did for the question container.


border: 1px solid white;
border-radius:40px;
box-shadow:10px 10px 15px black;

That should do for our label. One more thing we can do to our label is to add an hover effect such that once a user mouse over the label, we have a different background-color. To achieve this we use the :hover pseudo class on the label.


label:hover{
background:linear-gradient(10deg,#814302,rgb(200,142,13),#a74900));
}

For this hover effect, we're changing its background color to a merge of clay brown, daffodil yellow and tomato red, all inclined at 10degrees.

The next thing we want to consider is our selector(the radio button), and this is how we target it.


input[type=radio]{
}

We set it width and height to 30px, we also add a margin top and left property so it is aligned inside of our label element just as we would have wanted.


width:30px;
height:30px;
margin-top:35px;
margin-left:15px;

We're done with that now, let's move on. So the next thing we want to style is the span element which is to hold our option answers which we're yet to populate from JavaScript.


span{ }

We add a 50px font size to the span text, we add a margin-left property to move our span away from the radio button selector, we also include a white text color and a text shadow to our span text.


font-size:50px;
margin-left:30px;
color:white;
text-shadow:10px 10px 15px black;

That should be all for our span container as well as our options container. We can still notice that our options container is just too close to our question container, instead of having to individually space the label from the top which is possible, we can make it all simple by calling out the options class and adjusting its margin-top.


.options {
margin-top:50px;
}

We have the nextButton container in mind next, let's add it's styling and come back to explain a few of its properties.


#nextbutton{
width:400px;
height:120px;
color:white;
font-size:50px;
margin-top:50px;
margin-left:580px;
font-weight:bolder;
background:linear-gradient(10deg,rgb(6,104,178),#031060,rgb(4,60,123));
border-radius:70px;
border:2px solid white;
outline:none;
box-shadow:10px 10px 15px black;
}

What we did here isn't that difficult, we started with declaring a height and width for the button, we increased it's font size, set it's color to white and then worked with the margin top and left to move our button to our desired position (which is below the label container). We made it's text font weight bolder, added the same background-color as that of the question container, set its border-radius to 70px to have its edges curved. We also proceeded to add a 2px white border color having a solid border style. Buttons will always have outlines and since we don't have need for it we set it to none and then we also add a box shadow to the element.

We can now also add an hover to the button by changing its background-color to a somewhat lighter blue color.


#nextbutton:hover{
background:linear-gradient(10deg, #041060,rgb(6,104,178),#031060));
}

We are done styling the quizcontainer, we can go ahead to populate it's questions and options from JavaScript or we could style our result container so we know we're done with everything before moving on to JavaScript.

I think the second option sounds preferably okay, so let's go with that. It won't make any sense trying to style what we can't see as it is supposed to be hidden from display.

What we can do is set the display of the quizcontainer to none and set that of the result to block, for the mean time, so we see what effect we are adding. We set the result container width and height to 1000px and margin top to 200px, just as we did for the quizcontainer. We also set its font-size to 70px, centrally align its content and add to it a white text color. We also include a border radius and background color same as that of the quizcontainer.


#result {
display:none;
width:1000px;
height:1000px;
margin-top:200px;
font-size:70px;
color:white;
text-align:center;
border-radius:70px;
background:linear-gradient(10deg,rgb(6,104,178),#031060,rgb(4,60,123));
}

So we move on to the result score which also is to be populated from JavaScript, let's add a few styling to it.


#resultscore{
position:absolute;
width:1000px;
height:400px;
text-align:center;
margin-top:300px;
}

One more last thing before we conclude styling for this result container. We'll have to style the retry link.


#retry{ }

We'll display it block, so it starts a new line and take up its available sizing. We also position it absolutely providing a width and height for it. We use the margin top and left property to rightfully place it where it needs to be.


#retry{
display:block;
position:absolute;
width:400px;
height:120px;
margin-top:720px;
margin-left:300px;
}

We can also add a white text color to its text, increase its font-size, make it bolder using the font weight property and also adding a line heightso it is centrally placed in the container. After that we go ahead to add a background-color, border, border-radius and box-shadow. I believe your conversant with all of this properties by now.


text-decoration:none;
color:white;
font-size:50px;
font-weight:bolder;
line-height:98px;
background:linear-gradient(10deg,rgb(6,104,178),#031060,rgb(4,60,123));
border-radius:70px;
border:2px solid white;
box-shadow:10px 10px 15px black;

That's all for the retry link, the link is to redirect a user back to the start page of the question.

Remember, we changed the display of the quizcontainer to none so we could see what stylings we added to the result container. Let's go back to undo this, since we want the quiz container to be displayed first and the result container displays only if conditions are met (i.e questions have been completed).


#quizcontainer{
display:block;
//--> other necessary css
}
#result{
display:none;
//--> other necessary css
}

This would bring back our quiz container to page. We've spent enough time here already, let's get to the interesting part of the code where we will populate the questions from JavaScript into the page.


<script type="text/javascript"> </script>

The first script we need is a script containing an array of questions, each indexes having an object which in turn is going to hold the values of the question, option1, option2, option3, option4 and answer.


var questions = [
{
question:"_________ are values of qualitative variables belong to a set of items.",
opt1:"A:Data",
opt2:"B:Visual",
opt3:"C:Information",
opt4:"D:Analysis",
answer:"A",
},
{
question: "_________ Are typically the results of measurements and, can be visualizes using graphs or images",
opt1:"A.Visual",
opt2:"B.Information",
opt3:"C.Analysis",
opt4:"D.Data",
answer:"D",
},
{ question: "_________ is the end product of data processing",
opt1:"A:Data",
opt2:"B:Listed",
opt3:"C:Analysis",
opt4:"D:Information",
answer:"D",
},
{ question:"Data that are not given numerically are called?",
opt1:"A:Display",
opt2:"B:Monotative",
opt3:"C:Quantitative",
opt4:"D:Information",
answer:"C",
},
{ question: "Data that takes on numerically values e.g. shoe size, number of brothers, numbers of cars are called? ……………………",
opt1:"A:Qualitative",
opt2:"B:Monotative",
opt3:"C:Quantitative",
opt4:"D:Numerical",
answer:"C",
},
{question: "Another name for Quantitative data in ………………? ",
opt1:"A:Categorical",
opt2:"B:Analysis",
opt3:"C:Discrete",
opt4:"D:Working",
answer:"A",
},
{question: "_________ data mixes numerically and categorical data.",
opt1:"A:Primary",
opt2:"B:Secondary",
opt3:"C:Ordinal",
opt4:"D:Qualitative",
answer:"C",
},
{question: "_________ data represent measurements; their possible values cannot be counted and can only be described using intervals in real number?",
opt1:"A:Discrete",
opt2:"B:Secondary",
opt3:"C:Continuous",
opt4:"D:Primary",
answer:"C",
},
{question: "_________ Data is though of being uncountably infinite ",
opt1:"A:Ordinal",
opt2:"B:Continous",
opt3:"C:Quantitative",
opt4:"D:Qualitative",
answer:"B",
},
{question: "Data that represent items that can be counted and takes on possible values that can be listed out are ………………",
opt1:"A:Discrete",
opt2:"B:Analytical",
opt3:"C:Numerical",
opt4:"D:Quantitative",
answer:"A",
}
]

I clearly can recall stating that object properties are presented as name:value pairs which is always separated by a colon, in that object and arrays JavaScript tutorial. Atleast you can see how we present it. Also remember that arrays are separated by commas, its indexing starts from zero. This will be very useful as we go down the script.

Now that we have the questions and options intact, let's resolve on a way to send it to the quiz interface. We'll initialize the count and score to 0.


var count = 0;
var score = 0;

The count is going to serve as our counter for the question, so we can always update it once the criteria for nexting the question is met. We've also initialize the score to 0, probably because we want to update it once the selected answer matches that in our questions array.

We also want to have a special effect such that once we reach the last question, the content of the nextquestion container changes from "Next Question" to "Finish". We can only do that if we know the total questions in the question array. So we use the

.length
property to get the length of the questions array and assign to it a variable
totalQues


var totalQues = questions.length;

Trust me, it is always a good programming practice to declare all variables at the beginning of a script. We'll use the Html DOM method (document.getElementById()) to get at our Html element, assign them a variable which we're later going to use in our functions.


var quizContainer = document.getElementById('quizContainer');
var questEl = document.getElementById('question');
var opt1 = document.getElementById('option1');
var opt2 = document.getElementById('option2');
var opt3 = document.getElementById('option3');
var opt4 = document.getElementById('option4');
var nextQues = document.getElementById('nextbutton');
var retry = document.getElementById('retry');
var result = document.getElementById('result');
var resultScore = document.getElementById('resultscore');

Now we've gotten all our html element and assign to them variables, let go create a function that loads the questions from the question array. We can decide to call it just anything, we also pass it a parameter questionIndex.


function loadQuestion(questionIndex){
}

Let's get the question index and assign to it a variable q.


var q = questions[questionIndex];

The next thing we want to do is; change the text content of the questEl and the opt(1,2,3,4) to that of the question array.


questEl.textContent = q.question;
opt1.textContent = q.opt1;
opt2.textContent = q.opt2;
opt3.textContent = q.opt3;
opt4.textContent = q.opt4;

That's all for the loadQuestion(), we manually call out this function setting its parameter to our counter "count". And since the counter has not been updated it will print the first question which is at index 0.


loadQuestion(count);

At this time the next button is not working, so we can't next questions. This is not what we want, let's go create a function for the next button.


function nextButton(){

}
Crosscheck to see if the name matches that of the onclick attribute in the markup for the nextbutton container.

Now for the next button function, we will assign a variable "selectedOption" to query the selector (radio button), checking to see if it has be checked or not.


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

If it has not been checked we prompt an alert telling the user to select an option and return him back to the question.


if(!selectedOption){
alert("select an option");
return;
}

If an option has been checked or selected, we get this options' value and assign to it a variable

answer
.


var answer = selectedOption.value;

We can then go ahead to compare this answers to the answer we have in our questions array. If it matches, we increment score by 10. And uncheck the selectedOption and next the question by incrementing the count.


if(questions[count].answer==answer){
score+=10;
}
selectedOption.checked = false;
count++;

Now for the part, where we wanted to change the content of the "nextButton" to "Finish" for the last question. We can check if the counter

count
is equal the
totalQues-1,
if it does we set the text content of the next button to Finish. Let's break this down a bit.

Suppose we have 10 questions in our question array, the

count
which is the question index is going to start from 0 and end up at 9. Also the
question.length
property which is the totalQues does not start from 0, rather it starts from 1 and is going to end up at 10. We now know that the index for our last question is 9, so to get at it, we subtract 1 from the totalQues.


if(count==totalQues-1){
nextbutton.textContent = "Finish";
}

Okay, so once a user hits on the Finish button, we intend to hide the quiz container and display the result container. We also change the text content of the resultscore to some congratulatory message including the score and returning them all, back to the screen.


if(count==totalQues){
quizContainer.style.display = 'none';
result.style.display = 'block';
resultscore.textContent = 'You have done a nice job by finishing this quiz. Congratulations your score is:'+ ' '+score+'%';
return;
}

We can now call the loadQuestion() function using the counter as it parameter.


loadQuestion(count);

Our first question is loaded manually, that's why you have the loadQuestion function in the nextbutton function and outside the function.

Note; we can improve the quiz further by randomization of the questions, we could also add features like instant score updater and so much more. Wanna know how? Subscribe to our news feed, so we constantly update you for newer article. Leave comments on what you are not really cleared on let's walk you through.

No comments:

Post a Comment