3
votes

I am creating a dynamic form generator component in which the DOM controls to be displayed are getting populated from an API service. The model key i.e. the :v-model is also getting added dynamically. I am not able to access the data which the user inputs in the DOM control.

The component from where all the data is passed to the form-generator

<template>
   <form-generator :schema="schema" :model="model" :options="formOptions"></form-generator>
</template>
<script>
   export default {
      components: {
        FormGenerator
      },
      data() {
        return {
          model: {},
          schema: {
            fields: [{"id":"dcno1","label":"DC No.","model":"dcno","name":"dcno","ref":"dcno","className":"","type":"input","inputType":"text","required":true,"order":2}]
          }
      }
    }
</script>

In the above code, model and schema.fields are getting populated from an async axios API call.

If we pass value in the model for the model named "dcno", the value is getting filled in the input control


Dynamic Form Generator Component

<template>
   <v-form v-if='schema!==null' v-model="model.valid" ref="form" lazy-validation>
     <v-flex xs6 v-for='(formItem,index) in schema.fields' v-bind:key='index'>
         <v-text-field :v-model='formItem.model' ref="formItem.model" 
            :label='formItem.label' :rules='formItem.rules' 
            :value='model[formItem.model]'
            :type='formItem.inputType' :value='model[formItem.model]' 
            :id='formItem.id'>
         </v-text-field>
      </v-flex>
      <v-btn class='float-right' color="primary" @click="submitForm">Submit</v-btn>
   </v-form>
</template>
<script>
   export default {
     name: 'form-generator',
     components: {
     },
     props: {
     schema: Object,
     model: Object
     },
     methods:{
         submitForm: function(e) {
            //how to access the form model values here
         }
     }
   }
</script>

When passed a static value to model dcno, :value='model[formItem.model]', the value is getting displayed. Consider the fields key has a set of controls. Please help me in getting the values of the form in the submit function.

1
I can suggest you reading about two way data binding in custom components HERE - Vanojx1
What is the purpose of having both :v-model and :value? (Also, why the colon on :v-model?) - Roy J
Examine this.$refs['formItem.model'] in your submitForm function. - Roy J
@RoyJ this.$refs['formItem.model'] is giving array of all the form controls. :value is used to bind the values which are already populated from another API. - Jivan
You should try something like :ref="formItem.model" instead, that should create a unique reference for this item instead of an array. - Hammerbot

1 Answers

1
votes

As you can see in the docs you cannot change the value of a component property, you need to create a support object inside the inner component and emit its value to the main component. Take a look at the example, i create innerModel based on the schema structure then i emit every changes to the innerModel by watching it.

Vue.config.devtools = false;
Vue.config.productionTip = false;
const formGenerator = Vue.component('form-generator', {
  props: ['schema', 'value'],
  data() {
    return {
      innerModel: [],
    }
  },
  watch: {
    schema: {
      deep: true,
      immediate: true,
      handler() {
        this.innerModel = this.schema.fields.map((field) => ({
          // pass here any other property you need
          name: field.name,
          value: field.model,
        }));
      },
    },
    innerModel: {
      deep: true,
      immediate: true,
      handler(value) {
        this.$emit('input', value);
      },
    }
  },
  methods: {
    submitForm: function(e) {
      e.preventDefault();
      // convert innerModel into an object if needed
      console.log(this.innerModel);
    }
  },
  template: `
  	<form @submit="submitForm">
    	<input
      	:key="model.name"
        v-model="model.value"
        v-for="model in innerModel">
    	<button type="submit">SUBMIT</button>
    </form>
  `
})

new Vue({
  el: '#app',
  components: {
    formGenerator
  },
  data: {
    model: {},
    schema: {
      fields: [{
        id: "dcno1",
        label: "DC No.",
        model: "dcno",
        name: "dcno",
        ref: "dcno",
        className: "",
        type: "input",
        inputType: "text",
        required: true,
        order: 2
      }]
    }
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <form-generator :schema="schema" v-model="model"></form-generator>
  <h2>Changing model</h2>
  {{ model }}
</div>