1👍
There’s a lot of unknowns about the rest of your code (how the questions are handled and switched through, etc.), but here’s a working example for a single question. So you’ll have to adapt this for having multiple questions in your app, but it should push you in the right direction. I used an inline :style
attribute in addition to the static styles already present on the <li>
, but you could move that to a function as suggeted in Peter’s answer, if you prefer.
const app = {
name: 'Survey',
data() {
return {
n: 0,
questions: [],
answeredQuestions: [],
item: {
questionIndex: 1,
choices: ['Lorem', 'Ipsum']
},
selectedChoice: null
}
},
mounted() {
},
computed: {
questions() {
return this.$store.getters.survey;
},
},
methods: {
showNext() {
if (this.n < this.questions.length) {
this.n++
}
},
isAnswered(index) {
return this.n !== index ? 'hide' : '';
},
checkAnswer(questionIndex, choice) {
this.answeredQuestions.push(choice);
this.showNext();
}
}
};
Vue.createApp(app).mount('#app');
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.prod.js"></script>
<div id="app">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-action" :class="{disabled: answeredQuestions.length, active: answeredQuestions.includes(index)}" v-for="(choice, index) in item.choices" :key="index" @click.prevent="checkAnswer(item.questionIndex, index)">
<small class="">{{ index }}) {{ choice }}</small>
</li>
</ul>
</div>
1👍
You search the internet for vue class binding
and it’s the first result that pops up:
https://v2.vuejs.org/v2/guide/class-and-style.html
You can use an plain object, object from your data, a function returning an object or simply a string. You can make any attribute dynamic with v-bind:
, or simply :
.
Your checkAnswer()
function can cause a change in classes by manipulating something in data
, for example.
See tutorial above for example code. Keep in mind v-bind:class
is the same as :class
.
The "best way" changes like every week in Vue, just find a way to do it and learn its advantages and disadvantages.
An example would be:
template: let a function generate the classes
<small
:class="getChoiceClasses(item, choice, index)"
@click.prevent="checkAnswer(item.questionIndex, index)"
>{{ index }}) {{ choice }}</small>
script: add method
getChoiceClasses(item, choice, index) {
let classes = {
active: choice == 1, // for example
disabled: false, // default
even: index % 2 == 0
};
if (whateverYouNeedToCheck) {
classes.disabled = true;
}
return classes;
}
A method is a little slower than a value from data
, but it’s very minor and only becomes a problem when you have 100s of calls.
1👍
If I understand correctly your situation and what you intend to do here I would suggest using the item in the checkAnswer method so that an identifier is used to set a computed property to the current item.questionIndex.
Then you bind the class of each element with a ternary operator condition to check the questionIndex and return the proper classes string: <small :class="questionIndex == item.questionIndex ? ‘disabled active’:’disabled’" …