I am currently developing a quiz application using Vue 3 and Bootstrap 4.
One issue I encountered is with the function that checks if the selected answer is correct:
verifyAnswer(answer) {
return answer == this.results[this.questionCount]["correct_answer"];
}
This function should be triggered when a list item is clicked, as shown below:
<li v-for="answer in answers" @click="verifyAnswer(answer)" :class="{'text-white bg-success' : verifyAnswer(answer)}">{{answer}}</li>
If the chosen answer is correct, the list item should have the classes text-white bg-success
, otherwise it should have text-white bg-danger
.
const quizApp = {
data() {
return {
questionCount: 0,
results: [
{
question: "The book "The Little Prince" was written by...",
correct_answer: "Antoine de Saint-Exupéry",
incorrect_answers: [
"Miguel de Cervantes Saavedra",
"Jane Austen",
"F. Scott Fitzgerald"
]
},
{
question:
"Which novel by John Grisham was conceived on a road trip to Florida while thinking about stolen books with his wife?",
correct_answer: "Camino Island",
incorrect_answers: ["Rogue Lawyer", "Gray Mountain", "The Litigators"]
},
{
question:
"In Terry Pratchett's Discworld novel 'Wyrd Sisters', which of these are not one of the three main witches?",
correct_answer: "Winny Hathersham",
incorrect_answers: [
"Granny Weatherwax",
"Nanny Ogg",
"Magrat Garlick"
]
}
]
};
},
methods: {
nextQuestion() {
if (this.questionCount < this.results.length - 1) {
this.questionCount++;
}
},
prevQuestion() {
if (this.questionCount >= 1) {
this.questionCount--;
}
},
verifyAnswer(answer) {
// check if the clicked anwser is equal to the correct answer
return answer == this.results[this.questionCount]["correct_answer"];
},
shuffle(arr) {
var len = arr.length;
var d = len;
var array = [];
var k, i;
for (i = 0; i < d; i++) {
k = Math.floor(Math.random() * len);
array.push(arr[k]);
arr.splice(k, 1);
len = arr.length;
}
for (i = 0; i < d; i++) {
arr[i] = array[i];
}
return arr;
}
},
computed: {
answers() {
let incorrectAnswers = this.results[this.questionCount][
"incorrect_answers"
];
let correctAnswer = this.results[this.questionCount]["correct_answer"];
// return all answers, shuffled
return this.shuffle(incorrectAnswers.concat(correctAnswer));
}
}
};
Vue.createApp(quizApp).mount("#quiz_app");
#quiz_app {
height: 100vh;
}
.container {
flex: 1;
}
.questions .card-header {
padding-top: 1.25rem;
padding-bottom: 1.25rem;
}
.questions .card-footer {
padding-top: 0.7rem;
padding-bottom: 0.7rem;
}
.answers li {
cursor: pointer;
display: block;
padding: 7px 15px;
margin-bottom: 5px;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.1);
background: #fff;
}
.answers li:last-child {
margin-bottom: 0;
}
.answers li:hover {
background: #fafafa;
}
.pager {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
justify-content: space-between;
}
.pager li > a {
display: inline-block;
padding: 5px 10px;
text-align: center;
width: 100px;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 999px;
text-decoration: none !important;
color: #fff;
}
.pager li > a.disabled {
pointer-events: none;
background-color: #9d9d9d !important;
}
.logo {
width: 30px;
}
.nav-item {
width: 100%;
}
.card {
width: 100%;
}
@media (min-width: 768px) {
.nav-item {
width: auto;
}
.card {
width: 67%;
}
}
@media (min-width: 992px) {
.card {
width: 50%;
}
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script src="https://unpkg.com/vue@next"></script>
<div id="quiz_app" class="container questions d-flex align-items-center justify-content-center my-3">
<div v-if="results.length" class="card shadow-sm">
<div class="card-header bg-light h6">
{{results[questionCount]['question']}}
</div>
<div class="card-body">
<ul class="answers list-unstyled m-0">
<li v-for="answer in answers" @click="verifyAnswer(answer)" :class="{'text-white bg-success' : verifyAnswer(answer)}">{{answer}}</li>
</ul>
</div>
<div class="card-footer bg-white">
<ul class="pager">
<li><a href="#" @click="prevQuestion" class="bg-dark" :class="{'disabled' : questionCount == 0}">Previous</a></li>
<li class="d-flex align-items-center text-secondary font-weight-bold small">Question {{questionCount + 1}} of {{results.length}}</li>
<li><a href="#" class="bg-dark" :class="{'disabled' : questionCount == results.length - 1}" @click="nextQuestion">Next</a></li>
</ul>
</div>
</div>
</div>
The Issue
Surprisingly, the verifyAnswer(answer)
function gets called even before any click event occurs.
Query
What could be the mistake in my implementation?