4

I have quiet a complex v-for loop inside another v-for. Basically displays a list of questions and a list of answers for that question. I plan on getting the key for the question and using that for the key for grouped_answers.

The v-for loop is as follows:

        <div v-for="question in questions.questions">
          {{question.question}}
          <div v-for="a in grouped_answers[0].answers">
            {{a.answer}}
          </div>
        </div>

Currently returning an error of:

Cannot read property 'answers' of undefined.

The grouped_answers object example is here:

[
  {
    "question_id": 1,
    "answers": [
      {
        "id": 1,
        "answer": "Cat"
      },
      {
        "id": 2,
        "answer": "Dog"
      }
    ]
  },
  {
    "question_id": 2,
    "answers": [
      {
        "id": 3,
        "answer": "Fish"
      },
      {
        "id": 4,
        "answer": "Ant"
      }
    ]
  }
]

For the full template I have attached the code below:

<template>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
              <div v-for="app in appliances">
                <input type="radio" id="one" v-model="appliance"  v-bind:value="app.id" v-on:change="getQuestions">
                <label for="one">{{app.appliance}}</label>
              </div>
              <br>
              <span>Picked: {{appliance}}</span>
              </br>
              </br>
                <div v-for="co in brands">
                  <input type="radio" id="two" v-model="brand"  v-bind:value="co.id">
                  <label for="one">{{co.brand}}</label>
                </div>
              <span>Picked: {{ brand }}</span>
              </br>
              </br>
                <input type="radio" id="one" value=1 v-model="age">
                <label for="one">1 Year</label>
                <br>
                <input type="radio" id="two" value=2 v-model="age">
                <label for="two">2 Years</label>
                <br>
                <input type="radio" id="two" value=3 v-model="age">
                <label for="two">3 Years</label>
                <br>
                <input type="radio" id="two" value=4 v-model="age">
                <label for="two">4 Years</label>
                <br>
                <input type="radio" id="two" value=5 v-model="age">
                <label for="two">5 Years</label>
                <br>
                <input type="radio" id="two" value=6 v-model="age">
                <label for="two">6 Years</label>
                <br>
                <input type="radio" id="two" value=7+ v-model="age">
                <label for="two">7+ Years</label>
                <br>
              <span>Picked: {{ age }}</span>
              <br>
              <br>
                <div v-for="question in questions.questions">
                  {{question.question}}
                  <div v-for="a in grouped_answers[0].answers">
                    {{answers.answer}}
                  </div>
                </div>
              <br>
              <br>
              {{grouped_answers[0]}}
              <br>
              <br>
                <input v-model="first_name" placeholder="First Name">
                <p>First Name is: {{ first_name }}</p>
                <input v-model="last_name" placeholder="Last Name">
                <p>Last Name is: {{ last_name }}</p>
                <input v-model="phone_number" placeholder="Phone Number">
                <p>Phone Number is: {{ phone_number }}</p>
                <input v-model="email" placeholder="Email">
                <p>Email is: {{ email }}</p>
            </div>
        </div>
    </div>
</template>

<script>
    import axios from 'axios';
    export default {
      mounted() {
          console.log('Component ready.');

          console.log(JSON.parse(this.a));
          console.log(JSON.parse(this.b));

          this.appliances = JSON.parse(this.a);
          this.brands = JSON.parse(this.b);

      },

      props: ['a','b'],

        data: function() {
          return {
              appliances: '',
              appliance: '',
              brands: '',
              brand: '',
              age: '',
              first_name: '',
              last_name: '',
              phone_number: '',
              email: '',
              questions: '',
              answers: '',
              result: '',
              grouped_answers:'',
            }
        },
        methods: {
         getQuestions: function (){
           console.log(this.appliance);
           var self = this;
           axios.get('/get_questions/' + this.appliance, {

            })
            .then(function(response) {
                console.log(response.data);
                self.questions = response.data;
                self.getAnswers();
            })
            .catch(function(error) {
                console.log(error);
            });
         },
         getAnswers: function (){
           console.log(this.appliance);
           var self = this;
           axios.get('/get_answers/' + this.appliance, {

              })
              .then(function(response) {
                  console.log(response.data);
                  self.answers = response.data;
                  self.putAnswers();
              })
              .catch(function(error) {
                  console.log(error);
              });
         },
         putAnswers: function (){
           var result = {};

           for (var i = 0; i < this.answers.answers.length; i++) {
             var question_id = this.answers.answers[i].question_id;
             console.log(question_id);
             if(!result[question_id]) {
                result[question_id] = {question_id: question_id, answers: []};
              }
              result[question_id].answers.push({
                id: this.answers.answers[i].id,
                answer: this.answers.answers[i].answer})
           }
           result = Object.keys(result).map(function (key) { return result[key]; });
           console.log(result);

           this.grouped_answers = result;

           console.log(this.grouped_answers[0].answers);

         },
       },
    }
</script>

UPDATE AFTER RECOMMENDATION

        <div v-for="question in questions.questions">
          {{question.question}}
          <div v-for="a in grouped_answers[0].answers" v-if="grouped_answers">
            {{a.answer}}
          </div>
        </div>
6
  • Try to set v-if directive here - <div v-for="a in grouped_answers[0].answers" v-if="grouped_answers"> Commented Jan 24, 2017 at 19:26
  • Still having problems @BelminBedak, I have updated my answer with you suggestion Commented Jan 24, 2017 at 19:30
  • Okay, I guess getAnswers method is required for handling those data - but I can't see where you call this method ? I think it should be called into created() or mounted() hook. Commented Jan 24, 2017 at 19:36
  • are your console logs in putAnswers returning anything?
    – Eric G
    Commented Jan 24, 2017 at 19:40
  • It's the putAnswers method that handles the data which is called from the .then of the axios get request. All the methods work off the .then as that data isn't available until after the corresponding get request. Commented Jan 24, 2017 at 19:40

1 Answer 1

9

v-for takes priority over v-if so it is trying to run the loop before there is any data. To prevent this add a surrounding div or span and attach the v-if to that. Something like:

    <div v-for="question in questions.questions">
      {{question.question}}
      <div v-if="grouped_answers">
        <div v-for="a in grouped_answers[0].answers">
          {{a.answer}}
        </div>
      </div>
    </div>

And here is the documentation where they mention priority:

https://v2.vuejs.org/v2/guide/list.html#v-for-with-v-if

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.