Error compiling template/ Error in mounted hook

Viewed 25

I am having small trouble while testing Vuejs I don't know where to fix the Error

Error1: "[Vue warn]: Error compiling template:

Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.

1  |   <div v-if='counter < questions.length'> <h2>Question No. {{counter+1}} : {{questions[counter].question}}</h2></br> <span class=answer v-for='(answer, index) in questions[currentQuestion].answer' :key='index' v-bind:data-index='index' @click='selectAnswer'>{{ answer }}</span><p><button v-on:click='backBtn'>BACK</button><button class='next-btn' disabled>{{ currentQuestion < (questions.length -1) ? 'Next' : 'Result!' }}</button>  </p></div></div><div class='result'><div class='success'></div><h2>You have successfully finished the quiz, and your score is:</h2><h1 :class='[(Number(((correctAnswers / questions.length)*100)).toFixed(2) >= 50) ?'green' :'red']'>{{ Number(((correctAnswers / questions.length) *100)).toFixed(2) }}%</h1><small><b>{{ correctAnswers }}</b>Correct,<b>{{ wrongAnswers }}</b>Wrong</small><button class='close'>close</button><button class='show-wrong-ones'v-show='wrongAnswers > 0'@click='showWrongQuestion = true'>Wrong answers</button></div></div><div class='wrong-questions'><h2 v-if='wrongQuestions.length > 1'>Your wrong Questions</h2><h2 v-else-if='wrongQuestions.length == 1'>Your wrong Question</h2><div class='wrong-one' v-for='question in wrongQuestions'><h3>{{ question.question }}</h3><div class='answers-container'><span class='selected'>{{ question.answers[question.selected] }}</span><span class='correct'>{{question.answers[question.correct_answer] }}</span></div></div><button id='return-to-result'>Show my result</button></div></div>

Error2: "[Vue warn]: Error in mounted hook: 'TypeError: Cannot read properties of null (reading 'addEventListener')'

found in

---> "

HTML

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app1">
  <display-question></display-question>
</div>

JS with Vue2

Vue.component('display-question',{
  data: function(){
    return{
      counter: 0,
      currentQuestion: 0,
      answered: 0,
      showWrongQuestion: false,
      wrongQuestions: [],
      temp: [],
      wrongAnswers: 0,
      correctAnswers: 0,
    message: "Enter your answer here",
    WhatAnswer: "default",
    questions: [
      { 
        question: "What is 2+4 = ?",
        answer:[
          '2',
          '4',
          '6',
          '8'    
        ], 
        correctAnswer: 2,
        selected: null,
        sense: 0
      },
      {
        question: "What is 22+44 = ?",
        answer:[
          '33',
          '44',
          '55',
          '66'      
        ],
        correctAnswer: 3,
        selected: null,
        sense: 0
      }
    ]
  }},
  
  methods: {
    backBtn: function () {
      if (this.counter > 0) {
        this.answer = this.answer - 1;
      }
    },
    nextBtn: function(){
      if(this.answer < this.questions.length)
      this.answered = this.answered + 1; 
    },
     calculateResult: (questions) => {
      var correct;
      
      for(var i=0; i< questions.length; i++) {
        this.questions[i].selected == questions[i].correct ?  correct++ : '';
      }
return (correct / questions.length) * 100;
    },
    selectAnswer: function(a) {
      var choice = a.currentTarget,
          answers = document.querySelectorAll('.answers span'),
          nextBtn = document.querySelector('.next-btn');
      
      answers.forEach(answer => {
        answer.classList.contains('selected') ? answer.classList.remove('selected') : '';
      });
      
      choice.classList.add('selected');
      
      this.questions[this.currentQuestion].selected = choice.dataset.index;
 nextBtn.removeAttribute('disabled');
      
    },
  },
  mounted() {
    var nextBtn = this.$el.querySelector('.next-btn'),
        wrongAnswersBtn = this.$el.querySelector('.show-wrong-ones'),
        answers = this.$el.querySelectorAll('.answers span'),
        questionsLength = this.questions.length,
        result = this.$el.querySelector('.result'),
        question = this.$el.querySelector('.question'),
        closeResult = this.$el.querySelector('.result button.close'),
        wrongQuestions = this.$el.querySelector('.wrong-questions'),
        showMyResults = this.$el.querySelector('#return-to-result');
          
    nextBtn.addEventListener('click', () => {
      
      this.answered < this.questions.length ? this.answered++ : '';
      
      if(!nextBtn.hasAttribute('disabled') && this.currentQuestion < (questionsLength -1)) {    
        this.currentQuestion++;
        
        answers.forEach(answer => {
          answer.classList.contains('selected') ? answer.classList.remove('selected') : '';
        });
    nextBtn.setAttribute('disabled', '');
        
      } else if(this.currentQuestion >= (questionsLength -1)) {
        
        this.questions.forEach( (question) => {
          if(question.selected == question.correct_answer && question.sense ==0) {
            
            this.correctAnswers++;
            question.sense = 1;
            
          } else if(question.selected != question.correct_answer && question.sense ==0) {
            
            this.wrongAnswers++;
            question.sense = 1;
            let temp = {};
            temp.answers = question.answers;
            temp.question = question.question;
            temp.correct_answer = question.correct_answer;
            temp.selected = question.selected;
            
            this.wrongQuestions.push(temp);
          }
        });
    result.classList.add('active');
        question.classList.add('blur');
      }
    });
    
    closeResult.addEventListener('click', () => {
      result.classList.remove('active');
      question.classList.remove('blur');
    });
    
    wrongAnswersBtn.addEventListener('click', () => {      
      result.classList.remove('active');
      wrongQuestions.classList.add('active');
    });
    
    showMyResults.addEventListener('click', () => {
      result.classList.add('active');
      wrongQuestions.classList.remove('active');
      
    }) 
},
  template: ' <div v-if="counter < questions.length"> <h2>Question No. {{counter+1}} : {{questions[counter].question}}</h2></br> <span class=answer v-for="(answer, index) in questions[currentQuestion].answer" :key="index" v-bind:data-index="index" @click="selectAnswer">{{ answer }}</span><p><button v-on:click="backBtn">BACK</button><button class="next-btn" disabled>{{ currentQuestion < (questions.length -1) ? "Next" : "Result!" }}</button>  </p></div></div><div class="result"><div class="success"></div><h2>You have successfully finished the quiz, and your score is:</h2><h1 :class="[(Number(((correctAnswers / questions.length)*100)).toFixed(2) >= 50) ?"green" :"red"]">{{ Number(((correctAnswers / questions.length) *100)).toFixed(2) }}%</h1><small><b>{{ correctAnswers }}</b>Correct,<b>{{ wrongAnswers }}</b>Wrong</small><button class="close">close</button><button class="show-wrong-ones"v-show="wrongAnswers > 0"@click="showWrongQuestion = true">Wrong answers</button></div></div><div class="wrong-questions"><h2 v-if="wrongQuestions.length > 1">Your wrong Questions</h2><h2 v-else-if="wrongQuestions.length == 1">Your wrong Question</h2><div class="wrong-one" v-for="question in wrongQuestions"><h3>{{ question.question }}</h3><div class="answers-container"><span class="selected">{{ question.answers[question.selected] }}</span><span class="correct">{{question.answers[question.correct_answer] }}</span></div></div><button id="return-to-result">Show my result</button></div></div>' ,
    })
var test1 = new Vue({
  el: "#app1",
  data: {
  },
});
1 Answers

I encourage you to split your components to single-file components.

As Desribed here: https://v2.vuejs.org/v2/guide/single-file-components.html. As for your problems -

First problem - template should contain exactly one root element. that means that inside the template you need one tag to hold all of the other tags, meaning that your div tag should be the only root element in the component.

Second problem - nextBtn/closeResult/wrongAnswersBtn/showMyResults elements or at least one of them is null in the mounted hook. I encourage you to use v-on:click event. link to event handling in vue - https://v2.vuejs.org/v2/guide/events.html.

Hope it will help.

Related