newbiedev
newbiedev

Reputation: 3586

Vuejs - dynamically bind a class and execute function if a condition is meet

I'm trying to find a solution to three little problems in my vue app. The first one is about class binding. I have a bootstrap card that will display a question and relative answers. After the user clicks on a radio input, the answer is saved and the others options are disabled.

I'm checking dynamically if the user answer is correct but I'm unable to change the class of the card border dynamically. I want to have a black border before the answer is given and then if is right change the border class to border-success or border-danger if it's wrong. I've tried with this code but without success, the border will have the border-danger class also if no answer is given.

<div class="card text-dark bg-light border-secondary shadow mt-3 mb-3" :class="[userAnswers[qindex] === correctAnswers[qindex] && answered[qindex] ? 'border-success' : 'border-danger']">

Another small problem with the UI of the app is with the card footer. I have added a card footer that is not visible until the question displayed is answered. It will display the correct answer, but I've noticed that if a correct answer is given it will do a graphic glitch and will appear and then disappear.

<div class="card-footer bg-transparent border-success fw-bold" v-show="userAnswers[qindex] !== correctAnswers[qindex]">La risposta correttà è: {{ correctAnswers[qindex] }}</div>

To try fixing I've tested v-if and the actual v-show, also I've added a transition on the element with css but seems not work

.card-footer {
  transition: ease-in .3s;
}

The last and most important problem is with a conditional check. I want to show a modal when the user have answered to all the available questions. I've tried to add an if() statement in the mounted hook of vue but it will never be fired. I've also tried to call the method inside the .then() callback of the axios call that will check each question answer but without success.

export default {
  name: 'App',
  data(){
    return {
      isLoading: true,
      showResult: false,
      elaspedTime: null,
      questions: [],
      answered: {},
      userAnswers: [],
      correctAnswers: []
    }
  },
  mounted(){
    this.init();
    // statement will be never evalued 
    if( this.answered.length === this.questions.length ){
      this.quizResults();
    }
  },
  methods: {
    init(){
      axios({
        method: 'GET',
        url: 'http://localhost:8990/init'
      }).then( (res) => {
        this.questions = [];
        this.questions = res.data;
        console.log(this.questions);
        this.isLoading = false;
      });
    },
    checkAnswer(qindex, index, value){
      // console.log(qindex, index, value);
      this.answered[qindex] = true;
      this.userAnswers.push(value);
      axios({
        method: 'POST',
        url: 'http://localhost:8990/answercheck',
        data: {
          questionIndex: index,
          choice: value
        }
      }).then( (res) => {
        console.log(res.data);
        this.correctAnswers.push(res.data.correctAnswer);
        
      });
    },
    quizResults(){
// some logics after all the questions are answered 
      console.log('Results');
    }
  }
}

Can anyone help me to find a solution to fix these problems? Thank you.

Upvotes: 2

Views: 828

Answers (1)

Noy Gafni
Noy Gafni

Reputation: 1201

So you have 3 questions here.

Regarding your first question:

your problem is the wrap with [] of the condition of the class. this should solve it:

<div class="card text-dark bg-light border-secondary shadow mt-3 mb-3" :class="!userAnswers[qindex] ? ‘’ : userAnswers[qindex] === correctAnswers[qindex] && answered[qindex] ? 'border-success' : 'border-danger'">

Regarding your second question:

maybe there is a chance that when you are waiting for response form server, userAnswers[qindex] has value with the correct answer, and correctAnswers[qindex] is still undefined (until you gets the response), and at this split second they are not equal to each other - and this is why you see the footer for a second and then it disapears. so the solution is to check:

correctAnswers[qundex] && userAnswers[qindex] !== correctAnswers[qindex]

Regarding your third question

I think the best solution is to put the condition in the .then of checkAnswer() like you tried. Your problem is that you check this.answered.length but this.answered is an Object not an Array and it does not have .length propery. So you need to check if:

Object.keys(this.answered).length === this.questions.length

So your method should be:

checkAnswer(qindex, index, value){
      // console.log(qindex, index, value);
      this.answered[qindex] = true;
      this.userAnswers.push(value);
      axios({
        method: 'POST',
        url: 'http://localhost:8990/answercheck',
        data: {
          questionIndex: index,
          choice: value
        }
      }).then((res) => {
        console.log(res.data);
        this.correctAnswers.push(res.data.correctAnswer);
        if(Object.keys(this.answered).length === this.questions.length){
              this.quizResults();
        }
      });
    },

by the way the reason your condition did not work when you called it inside mounted() is because mounted called only when the component is loaded - it does not listen to changes. you can read more about it in vue docs

Upvotes: 1

Related Questions