Building a Progressive Quiz App with Vue, Vuex and Firestore: Part 3

Amenallah Hsoumi
7 min readMar 20, 2018

--

Quick note: I aplogize for releasing this a lot later than I promised.

This is part 3 of the tutorial series “Building a Progressive Quiz App with Vue, Vuex and Firestor”, and in this part we will start using firestore to create quizes.

links:

Now that we have finished authentication, we will move to actually creating, displaying and taking quizes. To achieve this, we will have 3 pages:

  • Home: this will display the latest quizes, and a fab button to take us to the quiz creation page and a link to display our quizes.
  • Create: quiz creation page
  • Test: this page will allow the user to take a quiz and display his result.

The Home Page

We will make a fab button that will take us to the quiz creation page. It will only be displayed when we’re logged in, otherwise we can’t create a new quiz. To keep things more organized, I will put the route views in a directory called pages. So go ahead and create it inside src and then we’ll create the Home.vue file:

src/pages/Home.vue

We used the “to” property of the v-btn to navigate using vue-router to the create route when it’s clicked. We’re also using the v-show directive to show the button only when the user is logged in. Now we need to add the page to the routes array and associate it with a url, we will do this inside router/index.js:

src/router/index.js

If you login you’ll see the fab button at the bottom right of the screen and if you click it, it will take you to the create page:

Coding the Quiz Builder

Creating a quiz will be done inside the create page, so let’s go ahead and create it’s initial layout:

src/page/Create.vue

We have 3 sections, first section is for the title and description of the quiz. Second section is for the quiz questions and possible answers. Third section is for quiz actions like cancelling or creating the quiz. We’ve also added a “to” attribute on the cancel button to bring us back to the home page when clicked.

Now we need to associate this page with a route, we’ll do it in the routes array like before:

And the result:

The quiz creator

Let’s discuss the quiz creation process. We will make creating a quiz simple. The quiz will have a title, a description, and a bunch of questions. So we will model it with two strings (title and description), and an array of questions.

Each question will be an object containing points, question title and a bunch of answers, so we will have a string, a number, and an array of answers. An answer has a text and a property called isRight that will be true if the answer is correct otherwise it will be false.

We will be using vuex to store the form data. So let’s update index.js inside store/quiz and create a sample of our quiz object:

store/quiz/index.js

and the result in the devtools:

Our create.vue component will get too big with all these input fields and logic. So let’s split it up to 3 sub components.

Quiz Information

The first one will be the quiz information and will contain a title and description text-fields. The component will mutate the new quiz title and description inside the store, so let’s first create the mutation. inside store/quiz let’s create mutations.js:

store/quiz/mutations.js

Now let’s implement this mutation inside the quiz module:

store/quiz/index.js

The mutation will recieve an object containing a title and a description and it will update the store with that data. Now let’s create our quiz information component that will grab the quiz getter and fill the input fields with the title and description, and when the user updates them, it will call the mutation:

src/components/quiz/QuizInformation.vue

First, we used the mapMutation method from vuex to map the update information mutation to a method inside the component. Second, we used the input event on the text fields to call a handler that will call the mutation everytime we make a change. The handler will recieve the new value as a parameter. We also used mapGetters to get the current quiz data, once the mutation updates the store, the component input fields will be updated too.

Let’s go ahead and use this component inside our Create.vue:

src/pages/Create.vue

Once we start editing the text fields content:

As you can see, the component is successfuly updating the state.

Quiz Questions

Nice, now we need another component that will display our questions and answers, updates question’s title and points, and add/update answers. We will call it QuizQuestions. First let’s make it display our questions, inside components/quiz let’s create QuizQuestions.vue:

src/components/quiz/QuizQuestions.vue

Now let’s include this inside Create.vue:

src/pages/Create.vue

And the result:

Let’s go ahead and implement those buttons logic.

Adding Answers

First we will start with add answer mutation:

we will implement it inside the module:

We add an answer by pushing a new object to the answers array of the question.

Now let’s call the mutation from our component when we click the button:

Removing Questions

Now, removing a question, same as before, add mutation, implement it, call it from the component:

src/store/quiz/mutations.js
src/store/quiz/index.js

We’re removing the question only if we have more than 1 left

src/components/quiz/QuizQuestions.vue

A better UX is to show a modal that asks the user if he really want to remove a question, that way if he didn’t do it on purpose he doesnt loose all his work on answers.

Removing Answers

src/store/quiz/mutations.js
src/store/quiz/index.js
src/components/quiz/QuizQuestions.vue

Updating Answers

We will update answers like we did with the title and description earlier. an update answer mutation will update both the answer’s isRight and answer attribute, we will create two methods for the two fields inside the component, let’s add the mutation:

src/store/quiz/mutations.js
src/store/quiz/index.js

The mutation will recieve a payload that contains a questionIndex and answerIndex, it will find the answer inside the array using the indexes and updates the properties of the object. Now inside our component we will map this mutation and use it twice to update the answer text and the isRight attribute:

src/components/quiz/QuizQuestions.vue

Updating Questions

The last thing left in the QuizQuestions component to do is to modify the question title and points, so let’s do that right now. A mutation as usual, and two methods:

src/store/quiz/mutations.js
src/store/quiz/index.js
src/components/quiz/QuizQuestions.vue

That’s it for the QuizQuestions components. Let’s give it a test:

The Create Quiz Footer

Now that our quiz is constructed inside the store, we can save is with firestore. First let’s create the footer of the card that will have the cancel/reset/create buttons, a total points counter, and a button to add another question. Let’s get the reset and add question mutation done:

We’ve added the add question and reset quiz mutation, let’s go ahead an code the add question first:

Now let’s create the component. We will have default actions like cancel and reset, and a dynamic action which will have the name and handler passed from parent. This will allow us to reuse this component later when updating a quiz by simply passing an update action name and handler instead of create:

The total points is a computed property that will re-compute everytime we add a question or modify a question’s points. Now let’s add this to the Create.vue:

Saving to Firestore

Aright, let’s create the create action to save our quiz to firestore. We will first get the current user uid, then check if there is a questions or not, then check if there is a question is without a right answer. Then attach the user id to the quiz object and save it to a collection which we will call “quizes”:

After creating a quiz and saving the data is inside our firetore:

The Home Page Revisited

Next, let’s display the quizes we have. For now, we will display them all until we implement an endless scrolling mechanism in the next tutorial. To display the quizes first let’s fetch them from firestore and save them in vuex:

src/store/quiz/mutations.js
src/store/quiz/index.js

Using the onSpanshot of the firestore collection, we will get realtime updates and push the new docs to our list inside the store. We’re emptying the list everytime we execute the action so that when we leave the home page and return we don’t have duplicate quizes. Now let’s create the QuizCard component that will represent a single quiz:

The component will choose a random color, so we will have random colors for each card. Now let’s call the list action from our Home.vue component when the component is created and loop over it to display the quizes cards:

Conclusion

This tutorial was going to be a bit long, so I decided to split it into 2 parts, creating the quiz, which is this one, and taking a quiz which will be in the next part.

--

--