2

I'm having trouble understanding why an array is undefined in my Vue component. Here is the flow:

  1. SelectCategories.vue component uses router to push to Quiz.vue component. Here I use props to pass on data to Quiz component. Here is how it is done:
      else {
        this.$router.push({
          name: 'quiz',
          params: {
            items: selectedCategories
          }
        })
      }

We move on to Quiz.vue component, where I do the following on the created life cycle hook:

    async created() {
        for (const item of this.items) {
            var questions = await QuestionService.getQuestionsByCategory(item);
            this.questions.push(questions);
            console.log(this.questions);
        }
  }

The QuestionService reaches out to the database and gets some information, which is pushed into the questions array I have defined here:

export default {
    name: 'quiz',
    props: ['items'],
    data: function() {
      return {
        questions: [],
        error: '',

      };  
    }

Finally, I try to access this data in the template using an h1:

<h1>{{questions[0][0].description}}</h1>

However, I end up with the following error:

TypeError: Cannot read property '0' of undefined

What I am seeing in the console is that:

{{questions[0][0].description}}

Is happening before I populate the questions array in the created life cycle hook. As you can see here:

enter image description here

It is my understanding that created is called before the template, but I might be wrong. What I want to accomplish is to have the functionality in created() have happen before the template is loaded, so the array gets populated first. Thank you for the help.

2 Answers 2

2

What I want to accomplish is to have the functionality in created() have happen before the template is loaded

.. this is not possible. Read more on JS asynchrony. await does not block the execution of whole app. created() hook just returns promise and is scheduled to continue when async call finishes.

Only way is to write your template in a way that the data are not present at first and will come later...

Sign up to request clarification or add additional context in comments.

Comments

2

Making created async and using await inside it does not prevent the component from being created and mounted. It only prevents the execution of code placed in created after await, until the promise resolves.

Which means your component will render without the expected contents in questions (until questions get updated, after the call returns).

The solution is to prevent anything currently breaking inside your component from breaking by wrapping those blocks in if conditions (or v-if in <template>).


A common solution for this type of problem is to make the call from outside the component and condition its rendering (creation) based on the response. Typically you want to place data that's consumed by more than one component in a store (single source of truth) which can then be injected anywhere you need it.

For more complex stores you could use Vuex and for very simple ones (basic data sharing) you could use Vue.observable().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.