Tutorial Goal: How to Develop Frontend Quiz App using VueJS

In this tutorial, we will learn and explore the fundamental concepts of how can we develop a frontend quiz app using VueJS. We all know how famous the VueJS framework is. Watch the below video to get idea of what are we developing.

So, without further ado, let’s get started with coding.

Create VueJS app

Here, we will be using Vue 2. Run the below command to create the VueJs app.

Copy Text
vue create quiz-app

You’ll see something like this.

Create VueJS app

Now, with the help of the following command navigate to the directory and run the server.

Copy Text
cd quiz-add
npm run serve 

The localhost will display the default screen as shown below.

default screen

Create User Interface

Every Vue component consists of three sections:

  • < template > containing HTML code of the component
  • < script > containing business logic
  • < style > containing CSS code for styling of the component

For our demo application, we will be having two components:

  • Quiz component
  • Modal component

Folder Structure

Here’s the image of our folder structure. It will be a pretty simple structure.

Folder Structure

Now let’s take a look at different files and see what are we going to do. Keep the note of the filename.

Keeping your app up to date can be very challenging in this fast-moving world of programming and development.
Hire Vue.js developer from us who are ready to fly with your flow to achieve your business goal strategically.

App.vue Set Up

App.vue is the parent file of all the components (here Quiz and Modal component). Let’s define our components. Refer to the following code for the UI template.

Copy Text
<template>
 <div id="app">
   <h2>Quiz App</h2>
   <quiz @quiz-completed="handleQuizCompleted" :key="quizKey" />
   <custom-modal
     v-show="showModal"
     header="Congratulations!"
     subheader="You've completed your Quiz!"
     :score="score"
     @reload="updateQuiz"
     @close="showModal = false"
   />
 </div>
</template>

Explanation

The code is quite simple.

  • v – show=” show Modal” will render the modal conditionally based on this . showmodal.
  • The score is a dynamic prop sent to modal from data properties.
  • The header and subheader are two static props.
  • The reload and close are the custom events that is called from modal-footer.

Moving on the < script > tag.

Copy Text
<script>
import CustomModal from "./components/CustomModal.vue";
import Quiz from "./components/Quiz.vue";
 
export default {
 components: { Quiz, CustomModal },
 name: "App",
 data() {
   return {
     quizKey: 0,
     showModal: false,
     score: {
       allQuestions: 0,
       answeredQuestions: 0,
       correctlyAnsweredQuestions: 0,
     },
   };
 },
 methods: {
   handleQuizCompleted(score) {
     this.score = score;
     this.showModal = true;
   },
   updateQuiz() {
     this.showModal = false;
     this.quizKey++;
   },
  },
};
</script>

Explanation

The logic will have two methods
1. handle Quiz completed ( ) : It receives the user score from the Quiz component and sets it to local state ‘this . score’. It is triggered by the custom event ‘quiz-completed’ that we’ve ] defined in the Quiz component.
2. update Quiz( ): The method will bind key to the ‘quiz Key’ data property. It will increment the ‘quiz Key’ by one that is further triggered by the ‘reload’ event from the CustomModal component.

Create Components

Further moving ahead with our tutorial to develop frontend quiz app using VueJS. Next we will start with our components: Quiz Component and CustomModal Component.

CustomModal.vue

The file CustomModal.vue will consist the UI and logic code of the modal. Refer to the code below.

Copy Text
<template>
 <transition name="modal">
   <div class="modal-mask">
     <div class="modal-wrapper">
       <div class="modal-container">
         <div class="modal-header">
           <h2>{{ header }}</h2>
           <h3>{{ subheader }}</h3>
         </div>
 
         <div class="modal-body">
           <div id="score">
             You answered
             <span class="highlight">
               {{
                 Math.floor(
                   (score.correctlyAnsweredQuestions / score.allQuestions) *
                     100
                 )
               }}
               % correctly!
             </span>
             Answered
             <span class="highlight">
               {{ score.correctlyAnsweredQuestions }} out of
               {{ score.allQuestions }}
             </span>
             questions.
           </div>
         </div>
 
         <div class="modal-footer">
           <button
             id="play-again"
             class="button-footer"
             @click="$emit('reload')"
           >
             Play Again
           </button>
           <button
             id="close-button"
             class="button-footer"
             @click="$emit('close')"
           >
             Close
           </button>
         </div>
       </div>
     </div>
   </div>
 </transition>
</template>
 
<script>
export default {
 props: {
   header: String,
   subheader: String,
   score: Object,
 },
};
</script>

Explanation

  • The score prop contains how many questions the user answered correctly and also contains total number of questions.
  • We use the score prop received from the Quiz component’s custom events. The modal-footer will have two buttons emitting custom events to reload and close the modal.

Quiz.vue

Here’s the code for the Quiz component.

Copy Text
<template>
 <div class="container">
   <div class="correctAnswers">
     You have
     <strong>{{ correctAnswers }} correct {{ pluralizeAnswer }}!</strong>
   </div>
   <div class="correctAnswers">
     Currently at question {{ index + 1 }} of {{ questions.length }}
   </div>
 
   <h2 v-html="loading ? 'Loading...' : currentQuestion.question" ></h2>
   <!-- Only first question is displayed -->
   <form v-if="currentQuestion">
     <button
       v-for="answer in currentQuestion.answers"
       :index="currentQuestion.key"
       :key="answer"
       v-html="answer"
       @click.prevent="handleClick"
     ></button>
   </form>
 </div>
</template>

Explanation

  • “loading ? ‘Loading…’ : currentQuestion.question” will check the loading property and based on it will decide ‘Loading…’ or the currentQuestion.
  • The answer of every question will be stored in the array answers. So, we will loop the answers with the help of ‘v-for’ and display every answer as the button element. With that, v-html=”answer” will display answer on the button.
  • The logic will be executed by handleClick that we will see later in the script part.

Here’s the logic part of the Quiz component. Let’s pick a method one at a time and see what the logic is about.

Fetch Questions

The prop ‘questions’ is intialized with an empty array. When the ‘loading’ is true, using Trivia API, we will fetch the questions and when the component will mount we will push them to the array. Here, five questions will be fetched every time an API call is made.

Copy Text
async fetchQuestions() {
     this.loading = true;
     //fetching questions from API
     let response = await fetch(
       "https://opentdb.com/api.php?amount=5&category=21&type=multiple"
     );
     let index = 0; //To identify single answer
     let data = await response.json();
     let questions = data.results.map((question) => {
       question.answers = [
         question.correct_answer,
         ...question.incorrect_answers,
       ];
       //shuffle above array
       for (let i = question.answers.length - 1; i > 0; i--) {
         const j = Math.floor(Math.random() * (i + 1));
         [question.answers[i], question.answers[j]] = [
           question.answers[j],
           question.answers[i],
         ];
       }
       //add right answers and key
       question.rightAnswer = null;
       question.key = index;
       index++;
       return question;
     });
     this.questions = questions;
     this.loading = false;
   },

Display Current Question

The computed property currentQuestion() will return the current question at the current index.

Copy Text
currentQuestion() {
     if (this.questions !== []) {
       return this.questions[this.index];
     }
     return null;
   },

Count Correct Answers

The below code snippet is to keep count of the correct answers.

Copy Text
correctAnswers() {
     if (this.questions && this.questions.length > 0) {
       let streakCounter = 0;
       this.questions.forEach(function (question) {
         if (!question.rightAnswer) {
           return;
         } else if (question.rightAnswer === true) {
           streakCounter++;
         }
       });
       return streakCounter;
     } else {
       return "--";
     }
   },

Calculate score

The below logic will calculate score. The ‘score()’ will use a reducer array prototype to reduce the current questions array to a n number. It returns the ‘score’ object that we use in the customModal component.

Copy Text
score() {
     if (this.questions !== []) {
       return {
         allQuestions: this.questions.length,
         answeredQuestions: 
     this.questions.reduce((count, currentQuestion) => {
           if (currentQuestion.userAnswer) {
             // userAnswer is set when user has answered a question, no matter if right or wrong
             count++;
           }
           return count;
         }, 0),
         correctlyAnsweredQuestions: this.questions.reduce(
           (count, currentQuestion) => {
             if (currentQuestion.rightAnswer) {
               // rightAnswer is true, if user answered correctly
               count++;
             }
             return count;
           },
           0
         ),
       };
     } else {
       return {
         allQuestions: 0,
         answeredQuestions: 0,
         correctlyAnsweredQuestions: 0,
       };
     }
   },

Watcher on Quiz Completion

We will keep watcher on quizCompleted() and if the quiz is completed, it will emit the event and display the score using this.score to App component.

Copy Text
 watch: {
   quizCompleted(completed) {
     completed &&
       setTimeout(() => {
         this.$emit("quiz-completed", this.score);
       }, 3000);
   },
 },

Check Correct Answer

To check correct answer. For that, it will compare userAnswer, answer given by user, and correct_answer, answer given by API. It further sets ‘.rightAnswer’ and ‘.wrongAnswer’ accordingly and manages the index state for moving on to the next question.

Copy Text
checkCorrectAnswer(e, index) {
     let question = this.questions[index];
     if (question.userAnswer) {
       if (this.index < this.questions.length - 1) {
         setTimeout(
           function () {
             this.index += 1;
           }.bind(this),
           3000
         );
       }
       if (question.userAnswer === question.correct_answer) {
         /* Set class on Button if user answered right, to celebrate right answer with animation joyfulButton */
         e.target.classList.add("rightAnswer");
         /* Set rightAnswer on question to true, computed property can track a streak out of 20 questions */
         this.questions[index].rightAnswer = true;
       } else {
         /* Mark users answer as wrong answer */
         e.target.classList.add("wrongAnswer");
         this.questions[index].rightAnswer = false;
         /* Show right Answer */
         let correctAnswer = this.questions[index].correct_answer;
         let allButtons = document.querySelectorAll(`[index="${index}"]`);
         allButtons.forEach(function (button) {
           if (button.innerHTML === correctAnswer) {
             button.classList.add("showRightAnswer");
           }
         });
       }
     }
   },

Run the server

After running the server, hit the browser and your UI will look something like this

Run the server

On clicking the answer you will know whether your answer is correct or not and simultaneously display next question. At the end of the quiz you will have the score board that will display your correct answer(s).

Github Repository: VueJS Quiz App

Feel free to visit the github source code: VueJS Quiz App and clone the repository to play around with the code.

Conclusion

So, this was about how to develop frontend Quiz app using VueJS. Are you a keen learner for VueJS? If yes, then VueJS tutorials page is for you! Visit different tutorials and start diving deep in advanced VueJS knowledge or polish your fundamentals for VueJS as well.

React vs Angular vs Vue: Infographic

Read Now

Get In Touch

[email protected]

Your Success Is Guaranteed !

We accelerate the release of digital product and guaranteed their success

We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.