Welcome back. In the first part of our project, we initialized our game, declared our first route, defined the store (Vuex) and get the questions from the API.

In this part we’ll take care of the logic of our game. So let’s start with it.

Original Repo:

https://github.com/omar1893/vue-quiz.git

Creating our components.

So first we need to create and import our components for our game and statistics of the game. So let’s create in our ‘components’ folder the following vue files:

Game.vue

Answers.vue

Question.vue

Each one with the basic structure of a .vue file:

<template>

<div>

This is x Component

</div>

</template> <script>

export default{}

</script> <style scoped>

</style>

Now let’s instantiate our new route in our ‘router/index.js’. First we gotta import it:

import Game from '@/components/Game'

And then let’s add the object inside the ‘routes’ array:

{

path: '/game',

name: 'game',

component: Game

},

You probably must be wondering “If I just created three components, why am I only instantiating the path of the ‘game’ component?”. Well, this is because I’m going to show you how to work with nested child components. Take a look at the next graphic (a.k.a masterpiece of design 😎 ):

Now this graphic means that the components ‘question’ and ‘answer’ (children) will be inside of ‘game’ (parent). The duty of ‘game’ will be to extract the questions array from our store, and just pass it to its children. The ‘question’ component will receive the question and just display it. The ‘answers’ component will show the options and besides that it will also handle the whole logic of the game.

There’s a lot of stuff to do. So let’s get it on:

Parent Component

First let’s work on our ‘components/game.vue’. First, we have to import the children component in order to use them. So inside our script tag let’s write the following:

import Question from './Question.vue'

import Answers from './Answers.vue'

Now, that we just imported these two components, we’re almost ready to use our children inside our parent component. Let’s put the following inside our export object:

components:{

question: Question,

answers: Answers

},

With this we just specified the name of the tags for each of the components that we need. So inside our component’s html let’s type the following:

<question></question>

<answers></answers>

Now we should see two ‘This is x Component’. Let’s add some style to our component. Remember these are the styles that I used. You can put your own:

<template>

<div class=”game”>

<div class=”card w-75 text-center py-4 mx-auto”>

<question></question>

<answers></answers>

</div>

</div>

</template>

After that, let’s create the data of our ‘game’ component.

data: function(){

return{

questions:[],

question:'',

object: {},

result:{

corrects:0,

incorrects:0

},

}

},

So let’s quickly explain the attributes of our component. First ‘questions’, this will hold the array of questions. Now, ‘question’ will have the string of the question that is active in our game. Then, ‘object’ this one will be the one to carry the active question object. ‘result’, will be the guy who takes care of the amount of fails and successes of the player.

Now that we understand that, let’s get serious with our game. At this point we should have in our store the questions. But, in order to use it we need to get to them from our ‘game’ component, so let’s do the following with our ‘questions’ attribute:

questions: this.$store.state.questions,

If we want to check, if this is working we can use the lifecycle hook, ‘created’, so let’s type the following:

created(){

console.log(this.questions)

}

Now every time that this component is created, it should print in our console the array that is inside of ‘questions’.

Remember: you need to go from the ‘start’ component to do the request to the API.

We now need to get the first question object of our array.To do that we need to write our first method. So let’s do it:

methods:{

getQuestion: function(answer){

this.object = this.questions.shift();

this.question = this.object.question;

}

}

With this method we take out the first question of our array and save it in the ‘object’ attribute, then we take the question string inside ‘object’ and save it in the ‘question’ attribute, now we need to call this method. We can use the lifecycle hook that we just created a moment ago in order to do that. So let’s add the following inside our ‘created()’ method:

created(){

this.getQuestion()

console.log(this.questions)

}

Now we need to start passing props to the children components. Let’s start with the simplest one, the ‘question’ component. We need to send the ‘question’ attribute to the proper component. In order to do that we gotta add to its html tag the following:

<question v-bind:question='question'></question>

With this we are basically saying that we are sending a ‘package’ called question (v-bind:question) and inside is our ‘question’ attribute (=’question’).

Now we need to display it in our screen. To do that we need to add some lines inside our ‘components/question.vue’ file. So let’s do it quickly. We’re not over with this component… yet.

Question Component.

This will be a short one. To display the question that is active in the parent, we need to add the following inside the export object:

props:[‘question’],

With that resolved we gotta replace the previous text and add the following line inside the html of this component:

<p>{{question}}</p>

Now we should see the first question displayed in our component. Pretty cool, but we should keep moving forward. So let’s go back to the ‘components/game.vue’ file.

Answers Component.

Now back into the ‘game’ component we need to add the following into the answers component in the html:

<answers v-bind:answers='object'></answers>

Now we’re passing the whole question object to the game component.

Now let’s go to the answers component, we’re not done yet here so we’ll come back again later. Now let’s go to the ‘components/answers.vue’ file.

First let’s instantiate the prop that this component will receive from the parent component:

props:['answers'],

Then let’s type the data of this component:

data () {

return{

options: [],

correct: '',

gameActive: true,

selected: '',

status: false

}

}

With that done, let’s explain it, because with these lines we just started the main logic of the game. So first, we have the ‘options’ array, this one will keep the options that we are going to display. The ‘correct’ attribute will hold the correct option for the active question. Then we have ‘gameActive’, this boolean will notify us that the user already took a choice and we should deactivate the buttons. The ‘selected’ attribute will have the option that the user took when he clicked one of the buttons. And finally, ‘status’, this one will change if the user is correct or incorrect, and will allow us to increment the score in the game component.

Now, we need to assign the props to the data. In order to do that let’s write the first method of this component.

methods: {

assign: function(){

this.options = this.answers.incorrect_answers,

this.correct = this.answers.correct_answer,

this.gameActive = true,

this.selected = ''

}

},

Then let’s use the lifecycle method ‘created’:

created(){

this.assign()

}

Now every time that this component is created we’ll have initialized our data with the active question.

Now let’s put some html into this component:

<template>

<div class='answers'>

<div class='container'>

<div class='row px-3'>

<div class='col-md-6" v-for=”option in options'>

<div class='multiple-choice'>

<button v-on:click='pickOption(option)' class='action-button animate w-100 mb-3'>

{{option}}

</button>

</div>

</div>

<button v-if='!gameActive' v-on:click='nextQuestion()' class='action-button animate w-100 blue my-3 bits'>

Next >

</button>

</div>

</div>

</div>

</template>

This is the basic html that I typed for this game, remember, I used bootstrap 4 for this game but you can use whatever you want.

Let’s explain the important parts of this html. First we have the v-for=’option in options’, with this, Vue should display the buttons of every option that we got in the ‘options’ array in our data. The v-on:click=’pickOption(option)’ is the method (that we’ll write soon) that will take the option that the user clicked and process it to know if the answer is right or wrong. With v-on:click=’nextQuestion()’ we’re going to go to the next question. And with v-if=’!gameActive’ we’ll only show this button if the game is inactive.

Now let’s write the ‘pickOption’ method:

pickOption: function(a){

this.gameActive = false;

this.selected = a;

if(this.correct == this.selected) this.status=true

else this.status=false

},

With this method, first we deactivate the game (at least in our data, for the moment…), then we save the selected option and compare it with the correct answer and check if the answer is right (this.status=true) or wrong (this.status=false).

Now we need to show the user if he picked right or wrong. To do this we need to play around with the classes of the button. But first let’s take a look to the logic of the classes and when we’re going to display each one.

If you are using the button styles that I told you in the first part of the tutorial, you’ll have 4 classes representing 4 colors (.blue, . red, .yellow, .blue), and besides that I have .disabled (pointer-events: none;), that just disables the buttons.

We are going to display this classes in the following situations:

blue: When the game is active.

When the game is active. disabled: When the game is inactive.

When the game is inactive. yellow: If the option chosen by the user is the option of this button AND the option chosen is wrong.

If the option chosen by the user is the option of this button the option chosen is wrong. green: If the game is inactive, AND the option chosen is the option of this button AND the option chosen is the correct one, OR if the game is inactive, AND the option chosen is the option of this button AND the option chosen is wrong.

If the game is inactive, the option chosen is the option of this button the option chosen is the correct one, if the game is inactive, the option chosen is the option of this button the option chosen is wrong. red: If the game is inactive.

So applying this situations we gotta type the following into the options buttons:

<button v-bind:class='{

blue: gameActive,

disabled: !gameActive,

red: !gameActive ,

yellow:selected == option && selected != correct,

green: !gameActive && selected == option && selected == correct || !gameActive && selected != correct && option == correct}'

v-on:click='pickOption(option)'

class='action-button animate w-100 mb-3'>

With this applied now we have the basic logic of our game. So right now we should be able to play… only the first question 😭. We need to create a method to make the parent component to update to the next question. It looks like this:

nextQuestion: function(){

this.$emit('nextQuestion', this.status);

}

This method just emits an event that the parent gotta listen and execute the getQuestion method. Plus, we are passing the status to update the counter on the ‘game’ component. But before we go to the ‘game’ component, we need a watcher to apply the ‘assign’ method every time the props are updated, so let’s use a ‘watch’ option in this component:

watch: {

'$props':{

handler: function (val, oldVal) {

this.assign()

},

deep: true

}

},

Now we’re ready to work again in the ‘game’ component.

Updating the question.

So right now, the only thing that’s left is to handle the events that are emitted by the ‘answers’ component. In order to do that let’s add the following inside the ‘answers’ tag.

<answers v-bind:answers='object' v-on:nextQuestion='getQuestion($event)'>

</answers>

With that done, we specified the event that the ‘game’ component is going to listen and the method that’s going to be executed.

Then, we need to update the ‘getQuestion’ method:

getQuestion: function(answer){

if(answer){

this.result.corrects++

}

else if(answer == false){

this.result.incorrects++

}

else if(answer == null){}

if(this.questions[0]){

this.gameActive = true;

this.object = this.questions.shift();

this.question = this.object.question;

}

else{

this.$store.commit('setResults', this.result);

this.$router.push({name: 'results'})

}

}

We did this to in order to update the score with the data that is coming from ‘answers.vue’. Then if there’s at least one object in the ‘questions’ array it will update the props. If there isn’t, it will set the counters of the game into our store, and move to the next view (we’ll see this in the next chapter).

Finally, we need to create this mutation in our store. So let’s work into ‘store/store.js’.

Setting the results of the game.

Now let’s create the mutation called ‘setResults’ to set the score of the player:

setResults(state, answers) {

state.results.correct_answers = answers.corrects;

state.results.incorrect_answers = answers.incorrects;

},

In this function we’re receiving the results object and setting the ‘results’ of our state.

With that done, we’re now ready with the basic logic of our game. The only things that are left in our game are:

Showing the score in the chart.

Uploading the score.

And receiving the whole list of the scores.

We’ll cover up these points in the next chapter.

See you then.