0👍
I’d recommend you to create a composable function. Define all your functions and state of the app like this:
// /src/composables/useQuestions.js
import {ref, onMounted, computed} from 'vue'
const questionArray = ref([])
const currentQuestion = ref(0)
const selectedAns = ref(null)
const computed_answer_options = computed(() => {
const questionObj = questionArray.value[currentQuestion.value]
if (questionObj) return questionObj.options
return []
})
const computed_question = computed(() => {
const questionObj = questionArray.value[currentQuestion.value]
if (questionObj) return questionObj.question
return null
})
export default () => {
onMounted(() => {
window.addEventListener("keyup", (event) => {
if (event.code == 'ArrowDown') {
nextQuestion();
}
else if (event.code == 'ArrowUp') {
previousQuestion();
}
});
})
// here you can call function that detect key releases and calls storeAnswer
// I did't finish logic, but i think you got the point
return {
questionArray,
currentQuestion,
nextQuestion,
previousQuestion,
computed_answer_options,
computed_question,
storeAnswer
}
}
const nextQuestion = () => {
if (currentQuestion.value < questionArray.value.length - 1) {
currentQuestion.value++;
}
}
const previousQuestion = () => {
if (currentQuestion.value > 0) {
currentQuestion.value--;
}
}
const storeAnswer = (ans) => {
selectedAns.value = ans
}
in your components use like this:
// App.vue, QuestionCard.vue
...,
setup () {
const {
questionArray,
currentQuestion,
nextQuestion,
previousQuestion,
computed_answer_options,
computed_question,
storeAnswer
} = useQuestions()
questionArray.value // returns []
}
- [Vuejs]-How do you add conditions to an array filter?
- [Vuejs]-Vue3 / Nuxt3 – how to use props directly in setup
0👍
I managed to solve my problem thanks to @Estus Flask, who pointed out my misusage of the Vue’s Composition API with Options API in my code.
Here’s the working code.
<script setup>
import { ref, onMounted } from 'vue';
import QuestionCard from "./components/QuestionCard.vue";
const questionArray = ref([
{
id: "123",
question: "Which of these is a colour in the rainbow?",
options: [
'brown', 'red', 'black',
],
selectedAns: null,
}, {
id: "456",
question: "How many continents does Earth have?",
options: [
1, 7, 6, 9
],
selectedAns: 6,
}, {
id: "789",
question: "Which of these is a prime number?",
options: [
7, 4, 44,
],
selectedAns: 4,
},
]);
const answerOptions = ref([]);
const currentQuestion = ref(0);
// methods to use in the App component -----------------------------------------------------------------
function nextQuestion() {
if (currentQuestion.value < questionArray.value.length - 1) {
currentQuestion.value++;
setAnswerOptions();
}
}
function previousQuestion() {
if (currentQuestion.value > 0) {
currentQuestion.value--;
setAnswerOptions();
}
}
function setAnswerOptions() {
answerOptions.value.length = 0;
for (let i=0; i < questionArray.value[currentQuestion.value].options.length; i++) {
answerOptions.value.push(
{
key: String.fromCharCode(65+i),
value: questionArray.value[currentQuestion.value].options[i]
}
);
}
}
// lifecycle hooks--------------------------------------------------------------------------------
onMounted(() => {
// console.log('App mounted, setting up listeners!!');
setAnswerOptions();
window.addEventListener("keyup", (event) => {
if (event.code == 'ArrowDown') {
nextQuestion();
}
else if (event.code == 'ArrowUp') {
previousQuestion();
}
const i = answerOptions.value.findIndex(element => element.key == event.key.toUpperCase());
if (i > -1) {
// console.log(`You have seleced ${answerOptions.value[i].value}, moving to next question`);
questionArray.value[currentQuestion.value].selectedAns = answerOptions.value[i].value;
nextQuestion();
}
});
// console.log('listeners all set!')
});
</script>
<template>
<div>
<div id='top_bar'>
<button @click=" previousQuestion ">Previous Question (Up key)</button >
<button @click=" nextQuestion ">Next Question (Down key)</button >
</div>
<div id='question_section'>
<QuestionCard
:id=" questionArray[currentQuestion].id "
:question=" questionArray[currentQuestion].question "
:answer_options=" questionArray[currentQuestion].options "
></QuestionCard>
<p v-if=" questionArray[currentQuestion].selectedAns != null ">
{{ 'Your last answer was: ' + questionArray[currentQuestion].selectedAns }}
</p>
<div id='answer_options_section'>
<ul>
<li v-for=" option in answerOptions ">
<button :class=" {'selected-option': option.value == questionArray[currentQuestion].selectedAns } " >
{{ option.key + ') ' + option.value }}
</button>
</li>
</ul>
</div>
</div>
</div>
</template>
QuestionCard.vue
<script setup>
import { ref } from 'vue'
// define the props used in this component
const props = defineProps({
id: String,
name: String,
question: String,
answer_options: Array,
});
</script>
<template>
<div>
<h5>Question ID: {{ id }}</h5>
<h4>{{ question }}</h4>
</div>
</template>
- [Vuejs]-Tailwind CSS with Nuxt3 grow text-area size dynamically
- [Vuejs]-How to call a method every single time the field loses focus in vue.js
Source:stackexchange.com