My first project using JavaScript
Tags: project, javascript, quiz
Published: 2020-11-02 15:19:36

This summer I joined the BlackCodher Bootcamp, which is an initiative of Coding Black Females and Niyo enterprise. The programme has the aim to empower black females with the skills and knowledge to start a career in Tech. I’m so far, really happy with all the resources and guidance we have been provided! As part of the course, we also get to build some projects. In this post, I will explain how I created a quiz using the skills I acquired. 

Feel free to play with the [demo](https://hawa-bah.github.io/), or check the code posted in [GitHub](https://github.com/hawa-bah/hawa-bah.github.io).

I chose to make the [quiz](https://hawa-bah.github.io/) about capitals cities, because, who doesn’t like to travel? It was built with HTML, CSS, JavaScript and jQuery. Here are the steps that you can follow. 

## 1. Store the questions in an array of objects. 
To start, in a Javascript file, I created an array of objects. Each object included a set of properties: a question, some options, and a correct answer. In my case, I also added an image related to the question, so that I could use it later to style the quiz. Make sure to export and import those variables that you will use in a different file. The following code only contains two questions, but feel free to add as many as you wish!
```javascript
const questions = [
    {
        qstn: ' What is the capital of Spain ?',
        options: ['Barcelona', 'San Marino', 'Madrid', 'Buenos Aires'],
        correct: 'Madrid',
        bgImage: "images/Madrid.jpg",
        country: 'Spain'
    },
    {
        qstn: ' What is the capital of Greece ?',
        options: ['Thessaloniki', 'Santorini', 'Mykonos', 'Athens'],
        correct: 'Athens',
        bgImage: "images/Athens.jpg",
        country: 'Greece'
    }]
```

## 2. Create an HTML file.
In the body of the HTML file, I firstly, created a ``<section>`` which includes the title of the quiz and some instructions. This is the first part the user will see, so a "Start" button has also been added before closing the section. As you can see from the code below, I have also added a "Restart" and "Check all Answers" button.
Moreover, I included an empty ``<div>`` container, this is because a function will be created in JavaScript to display the content of the quiz. Make sure to assign an id or a class to the elements, this way, it will be easier to select or access the element.
```HTML
 <body>
        <section class="home-container">
            <h1 class ="pageTitle">The Capital-City quiz</h1>
            <div class="home-sub">
                <p>How good are you in Geography? <br>Find out by playing this fun and educational game.</p>
                <p>INSTRUCTIONS:</p>
                <ol>
                    <li>Press the button Start to see the first question. </li>
                    <li>Select your answer, only one option is allowed.</li>
                    <li>You can click submit to check if you clicked the right answer. Then, click next to view the following question.</li>
                </ol>
                <p>Good Luck!</p>
                <button type="submit" id="btnsubmit">Check All Answers</button>
                <button id="start">Start</button>
                <button id="restart"><a href="./index.html">Restart Game</a></button>
                <br>
                <br>
            </div>            
        </section>
        <div id="quizDiv" ></div>
</body>
```

## 3. Build the quiz with JavaScript.
###3.1. Declaring the function
In a JavaScript file, I created a function ``buildQuiz()`` which would construct the quiz. To do this, I used the array ``questions`` created in step 1 as a parameter of the function. Inside ``buildQuiz()``, I have also used a method to get each of the elements I have previously created in the HTML file. In this case, I used the ID's which were assigned to the empty ``<div>`` and the button "Check All Answers".  
```javascript
function buildQuiz(questions){
    const quizDiv = document.getElementById('quizDiv');
    const btnsubmit = document.getElementById('btnsubmit');
   };
```
###3.2. Mapping each question 
Inside ``buildQuiz()``, I used the map method to create a ``<div>`` for each object of the array. This ``<div>`` would contain a question as a title, and a form to show the possible answers. For this project, I made a radio type form, but you could choose another type. Below the form, I also included a *submit* and *next* div. Don’t forget to append every element you have created in JavaScript!
``` javascript
    questions.map((question) => {
        const questionDiv = document.createElement('div');
        questionDiv.className = 'questionDiv';
        questionDiv.id = 'questionDiv' + question.correct;      

        const qstnTitle = document.createElement('h2');
        qstnTitle.textContent = question.qstn;
        qstnTitle.className = 'qstn';
        
        const optionsForm = document.createElement('form');
        optionsForm.className = 'optionsForm';

        const submitNextDiv = document.createElement('div');
        submitNextDiv.className = 'submitNextDiv';
                      
        const submitDiv = document.createElement('div');
        submitDiv.addEventListener('click', respondClick)
        submitDiv.className = 'submitDiv';
        submitDiv.textContent = 'Submit';
        
        const nextDiv = document.createElement('div');
        nextDiv.className = 'nextDiv';
        nextDiv.id = 'nextDiv';
        nextDiv.textContent = 'Next';
        
        submitNextDiv.appendChild(submitDiv);
        submitNextDiv.appendChild(nextDiv);
        questionDiv.appendChild(qstnTitle);
        questionDiv.appendChild(optionsForm);
        questionDiv.appendChild(submitNextDiv);
        quizDiv.appendChild(questionDiv);
       
        btnsubmit.addEventListener('click', respondClick);
   });
```
###3.3. Mapping each option
When creating the inputs for each possible answer, which will be appended in the form, I also used the ``.map()`` method to access each option of each question. So the following mapping is completed inside the scope of the previous map ``questions.map((question)``.
```javascript
question.options.map((option) =>{
            const optionDiv = document.createElement('div');
            optionDiv.id = 'optionDiv' + option;

            const inputForm = document.createElement('input');
            inputForm.type = 'radio';
            inputForm.name = question.correct;
            inputForm.id = option;
            
            const inputLabel = document.createElement('label');
            inputLabel.for = option;
            inputLabel.textContent = option;
            
            optionDiv.appendChild(inputForm);
            optionDiv.appendChild(inputLabel);
            optionsForm.appendChild(optionDiv);
        });
```
###3.4. Adding Event Listeners
As you may have spotted in step 3.2, we have added some event listeners to the "Check all answers" button and to *submitDiv*. Both of them have the same event handler ``respondClick()``, which defines the code that will run in response of the event. This function is declared in the scope of ``buildQuiz()``, more specifically, inside the first map function.
```javascript
function respondClick(){
            question.options.map((option) => {
                if(document.getElementById(option).checked && (option == question. correct)) {
                    const feedback = document.createElement('p');
                    feedback.textContent = 'You are right! ' + option + ' is the capital of ' + question.country;
                    questionDiv.appendChild(feedback);
                    //changing the style
                    let optionDiv = document.getElementById('optionDiv' + option);
                    optionDiv.style.color = 'green';
                    questionDiv.style.backgroundImage = " " + "url('" + question.bgImage + "')";
                    questionDiv.style.backgroundBlendMode = 'none';
                }
                if(document.getElementById(option).checked && (option !== question. correct)) {
                    const feedback = document.createElement('p');
                    feedback.textContent = 'Try again! ' + option + ' is not the correct answer...';
                    questionDiv.appendChild(feedback);
                    //changing the style
                    let optionDiv = document.getElementById('optionDiv' + option);
                    optionDiv.style.color = 'red';
                    optionsForm.style.backgroundColor = 'red';
                    questionDiv.style.backgroundImage = "linear-gradient(black, red), " + "url('" + question.bgImage + "')";
                    questionDiv.style.backgroundBlendMode = 'multiply';
                }
            })
        }
```
Let's look at the above event handler to see how it works. According to the option the user has selected, we want to display one message or another. For this reason, I used if statements. 
As for the conditions, we need to check whether the option has been selected and if the option is correct. Since we need to do this for each option of each question, we will need to use the map function once more. 
If the conditions are met, we will create a *feedback* element with a specific text content, and we will append it to the div that contains the question.
###3.5. Other event listeners with jQuery
To make the page scroll to the next question when the *next* div has been clicked, I used jQuery. The following function is inside the scope of the very first map method ``questions.map((question)``, because we are creating an event for each of the *next* div’s of each question. As you can see, I used a combination of ``.parent()`` and ``.next()`` to find which question I wanted to see once the *next* div has been clicked. I will refer to this question as *the target*. Then, I made an animation which would scroll the page down to the target.
```javascript
  $(".nextDiv").click(function() {
            var next;
            next = $(this).parent().parent().next();
            $('html,body').animate({scrollTop: next.offset().top});  
        })
```
Similarly, once the "Start" button is clicked, the page scrolls to the first question.
```javascript
$("#start").click(function() {
        var elmnt = document.getElementById("quizDiv");
        console.log(elmnt);
        elmnt.scrollIntoView();
     })
```

##4. Adding style
To add styling to the elements of the quiz, it can be more comfortable to assign a className to each element, and use it in the CSS. Nevertheless, it is also possible to add it in the same JavaScript file using this format: ``[elementName].style.[propertyName] = “[value]”`` .  Or if you want to add more than one property you can use: ``[elementName] .style.cssText= “[propertyName1]: [value1]; [propertyName2]: [value2]” ``. For instance:
```javascript
optionsForm.style.cssText = "  display: grid;  
            grid-template-columns: repeat(auto-fit, 186px);  
            grid-gap: 5px; color: white; font-family: 'Anton', sans-serif; 
            justify-content: center; margin: 20px; padding: 5px " ;
```
So, these were the main steps I followed to build the [quiz](https://hawa-bah.github.io/). It was a great way to improve my skills in Javascript and jQuery. Moreover, the structure gives me the flexibility of adding more questions or possible answers at any time.

If you want to know more about my coding journey, or just want to chat make sure to follow me [@HawaCodes](https://twitter.com/HawaCodes) on Twitter 💙.