Dave Nathaniel
Dave Nathaniel

Reputation: 39

V-model to dynamically created object in array

I have an array, I want to dynamically create objects in the array and v-model an input to it, this is what my code looks like:

This is the array

new_questions:{
    questionrecord: []
}

This is the input

<div class="form-fields" v-for="(field, index) in question_fields">
    <div class="form-group">
        <select class="form-control" v-model="new_questions.questionrecord[index].questionresponse">
            <option value="single_answer">Single Answer (For regular question)</option>
            <option value="multiple_answer">Multiple Answer (For situational judgement question)</option>
        </select>
    </div>
</div>

I expect to have an array that looks like

new_questions:{
    questionrecord: [
        {
            questiontype: "single_answer"
        },
        {
            questiontype: "multiple_answer"
        },
        ...
    ]
}

But I get an error:

[Vue warn]: Error in render: "TypeError: Cannot read property 'questionresponse' of undefined

How can I achieve this?

Upvotes: 0

Views: 2205

Answers (2)

MarcRo
MarcRo

Reputation: 2473

V-Model is only syntactic sugar for @input=".." and :value=".."

To manipulate data the way you described it might be necessary to distinguish the two and write a setterMethod that can handle dynamic (and possibly non-existant) properties.

Depending on the structure of your data, on whether you want to handle properties on different nested levels, etc., your setterMethod can become a little complex. Helpers like lodash.setWith could help out a bit.

A very specifig example for your case:

<template>
...
  <div class="form-fields" v-for="(field, index) in question_fields">
    <div class="form-group">
      <select class="form-control"
       :value="new_questions.questionrecord[index].questionresponse"
       @input="setValue($event.target.value, index)"
      >
        <option value="single_answer">Single Answer (For regular question)</option>
        <option value="multiple_answer">Multiple Answer (For situational judgement question)</option>
      </select>
    </div>
  </div>
...
</template>

<script>
export default {
  data() {
    return {
      new_questions: {
        questionrecord: [],
      }
    };
  },

  created() {
    // prepopulate your questionrecord array so you don't throw TypeErrors
    const dummyArray = Array(this.question_fields.length);
    this.new_questions.questionrecord.push(...dummyArray);
  },

  methods() {
    setValue(value, index) {
      const newRecord = {
        questionresponse: value,
      };
      // in order to create responsive array entries in vue, you have to use native array methods - don't set the value by index
      // (e.g. this.new_questions.questionrecorcd[index] = newRecord);
      this.new_questions.questionrecord.splice(index, 1, newRecord);
      // Object properties would need to be created with Vue.set(rootObj, key, value);
    }
  }
};
</script>

Upvotes: 1

Emīls Gulbis
Emīls Gulbis

Reputation: 2070

Don't know how looks your question_fields, but I tested with some dummy values and this code works for me.

new Vue({
  el: "#app",
  data() {
    return {
      question_fields: ['test', 'test1'],
    	new_questions:{
          questionrecord: [
              {
                  questiontype: "single_answer"
              },
              {
                  questiontype: "multiple_answer"
              }
          ]
      }
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div class="form-fields" v-for="(field, index) in question_fields">
    <div class="form-group">
      <select class="form-control" v-model="new_questions.questionrecord[index].questionresponse">
        <option value="single_answer">Single Answer (For regular question)</option>
        <option value="multiple_answer">Multiple Answer (For situational judgement question)</option>
      </select>
    </div>
  </div>
  
   <pre>{{new_questions.questionrecord}}</pre>
</div>

Upvotes: 0

Related Questions