Home > Software engineering >  Data is not coming if i use async in vue js 3
Data is not coming if i use async in vue js 3

Time:07-25

I am implementing Quiz App but here I am facing an issue if I put static data in array the questions are coming.

Data is not coming if i use async in Vue JS 3

But If I Call data from the API the questions are not showing.

when I console the questions are showing in console and not showing in the front end.

For ref please find the attached code and image.

Home.vue (please see fetchQuestionsFromServer function)

     <template>
      <main >
        <!-- quiz container -->
          <QuizComplatePage v-if="endofQuiz" />
        <div
          
        >
          <img
            src="@/assets/images/abstract.svg"
            alt=""
            
          />
    
          <!-- contents -->
          <div >
            <!-- score container -->
            <div >
              <p >Score</p>
              <p >{{score}}</p>
            </div>
    
            <!-- timer container -->
            <div >
              <div  
              :style= "`width: ${timer}%`"
              ></div>
            </div>
    
            <!-- question container -->
            <div
              
            >
              <div >
               {{currentQuestion.question}}
              </div>
            </div>
    
            <!-- options container -->
    
            <div >
              <!-- option container -->
              <div v-for="(choice,item) in currentQuestion.choices" :key="item">
                <div
                
                :ref="optionchosen"
                @click="onOptionClick(choice,item)"
              >
                <div
                  
                >
                  <p > 10</p>
                </div>
                <div >
                  <!-- option ID -->
                  <div >{{item}}</div>
    
                  <!-- option name -->
                  <div >{{choice}}</div>
                </div>
              </div>
              </div>
              <!-- option container -->
            </div>
    
            <!-- progress indicator container -->
            <div >
              <div ></div>
              <p >{{questionCounter}}/{{questions.length}}</p>
            </div>
          </div>
        </div>
      </main>
    </template>
    <script>
    import { onMounted, ref } from 'vue'
    import QuizComplatePage from './QuizCompleteOverlay.vue'
    export default{
      components: {
    QuizComplatePage
      },
      setup(){
        //data
        let canClick = true
        let score = ref(0)
        let timer = ref(100)
        let endofQuiz = ref(false)
        let questionCounter = ref(0)
        const currentQuestion = ref({
          question: '',
          answer: 1,
          choices: [],
        });
        const questions = []
    
    const loadQuestion = () =>{
      canClick = true
      timer.value=100
      //Check question array had questions or not
      if(questions.length > questionCounter.value){
         currentQuestion.value = questions[questionCounter.value]
         console.log('Current Question is : ', currentQuestion.value);
         questionCounter.value  
      }else{
        endofQuiz.value = true
        console.log('Out of Questions');
      }
     
    }
    
    
    //methods
    let itemsRef = []
    const optionchosen = (element) =>{
      if(element){
    itemsRef.push(element)
      }
    }
    
    const clearSelected = (divselected) =>{
      setTimeout(()=>{
      divselected.classList.remove('option-correct')
      divselected.classList.remove('option-wrong')
      divselected.classList.add('option-default')
      loadQuestion()
      },1000)
      
    }
    
    const onOptionClick = (choice,item) =>{
      if(canClick)
      {
        const divContainer = itemsRef[item]
      const optionId = item 1
      if(currentQuestion.value.answer ===optionId){
        console.log('You are Correct');
        score.value  = 10
        divContainer.classList.add('option-correct')
        divContainer.classList.remove('option-default')
      }else{
        console.log('You are Wrong');
        divContainer.classList.add('option-wrong')
        divContainer.classList.remove('option-default')
      }
      timer.value=100
      canClick=false
      //to go next question
      clearSelected(divContainer)
      console.log(choice,item);
      }else{
        console.log('Cant Select Option');
      }
    }
    
    const countDownTimer = () =>{
    let interval= setInterval(()=>{
      if(timer.value>0){
        timer.value--
      }else{
        console.log('Time is over');
        clearInterval(interval)
      }
    
     },150)
    }
    
    const fetchQuestionsFromServer = async function(){
       fetch('https://opentdb.com/api.php?amount=10&category=18&type=multiple')
      .then((res) =>{
        return res.json()
      })
      .then((data) =>{
        const newQuestions = data.results.map((serverQuestion) =>{
          const arrangedQuestion = {
            question: serverQuestion.question,
            choices: '',
            answer: ''
            
          }
          const choices = serverQuestion.incorrect_answers
          arrangedQuestion.answer = Math.floor(Math.random() * 4   1)
          choices.splice(arrangedQuestion.answer-1 , 0 , serverQuestion.correct_answer)
          arrangedQuestion.choices = choices
          return arrangedQuestion
        })
        console.log('new formated questions' , newQuestions);
        questions.value = newQuestions
        loadQuestion()
        countDownTimer()
        console.log('questions: =>' , questions.value);
        
      })
    }
    
    
    //lifecycle hooks
    onMounted(() =>{
      fetchQuestionsFromServer()
    })
    
    
      //return
        return {
          timer,
          currentQuestion, 
          questions, 
          score,
          questionCounter, 
          loadQuestion,
          onOptionClick,
          optionchosen,
          endofQuiz,
          }
      }
    }
    </script>
    
     <style scoped>
    .neumorph-1 {
      box-shadow: 6px 6px 18px rgba(0, 0, 0, 0.09), -6px -6px 18px #ffffff;
    }
    .container {
      max-width: 400px;
      border-radius: 25px;
    }
    </style>

QuizComplatePage.vue

    <template>
      
      <div >
    
        <div >
            <p >All DOne!</p>
            <p >100% Score</p>
    
            <!-- Buttons -->
            <div >
                <div >Done</div>
                <div >Retry</div>
            </div>
        </div>
    
      </div>
    </template>
    
    <script>
    export default {
        name: 'QuizComplatePage'
    
    }
    </script>
    
    <style>
    
    </style>

Image.

Please find the image also

CodePudding user response:

You are not using value when you need to:

For instance look in this function

questions.length should be questions.value.length

Also currentQuestion.value = questions.value[questionCounter.value]

Start by fixing that.

Everything that is a ref in your setup needs to be accessed by .value in anything inside your setup. Outside your setup it will have this and can be treated normally. Mixing these two up is the most common error.

const loadQuestion = () =>{
      canClick = true
      timer.value=100
      //Check question array had questions or not
      if(questions.value.length > questionCounter.value){
         currentQuestion.value = questions.value[questionCounter.value]
         console.log('Current Question is : ', currentQuestion.value);
         questionCounter.value  
      }else{
        endofQuiz.value = true
        console.log('Out of Questions');
      }
     
    }

CodePudding user response:

Here is my solution

let questions = []

questions = newQuestions

Now I am able to load questions.

  • Related