Dynamically adding different components in Vue

前端 未结 3 1787
时光说笑
时光说笑 2021-02-02 01:22

I want to create a simple form builder with Vue where users click on buttons from a menu to add different form fields to a form. I know that if there was just one type of form f

相关标签:
3条回答
  • 2021-02-02 01:54

    You can pass the field object as props of your form-input component and make the type dynamic:

    Vue.component('form-input', {
      template: '#form-input',
      props: ['field']
    })
    
    new Vue({
      el: '#app',
      data: {
        fields: [],
        inputType: '',
        count: 0
      },
      methods: {
        addFormElement(val) {
          this.fields.push({type: val, placeholder: 'Textbox ' + (++this.count)});
        }
      }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
    <div id="app">
      <h3>Add form element</h3>
      <select size="3" v-model='inputType' @click="addFormElement(inputType)">
        <option value="text">Text</option>
        <option value="checkbox">Checkbox</option>
        <option value="radio">Radio</option>
      </select>
      <p>
        <form-input v-for="field in fields" :field="field"></form-input>
      </p>
    </div>
    
    <template id="form-input">
      <div>
        <label>{{ field.type }}</label>
        <input :type="field.type" />
      </div>
    </template>

    0 讨论(0)
  • 2021-02-02 01:58

    Ok, so I looked into dynamic elements and managed to pull this together:

    Vue.component('form-input', {
      template: '#form-input'
    });
    
    Vue.component('form-select', {
      template: '#form-select'
    });
    
    Vue.component('form-textarea', {
      template: '#form-textarea'
    });
    
    new Vue({
      el: '#app',
      data: {
        fields: [],
        count: 0
      },
    
      methods: {
        addFormElement: function(type) {
          this.fields.push({
            'type': type,
            id: this.count++
          });
        }
      }
    })
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
    <div id="app">
      <component v-for="field in fields" v-bind:is="field.type" :key="field.id"></component>
    
      <button type="button" v-on:click="addFormElement('form-input')">Add Textbox</button>
      <button type="button" v-on:click="addFormElement('form-select')">Add Select</button>
      <button type="button" v-on:click="addFormElement('form-textarea')">Add Textarea</button>
    </div>
    
    <script type="x-template" id="form-input">
      <div>
        <label>Text</label>
        <input type="text" />
      </div>
    </script>
    
    <script type="x-template" id="form-select">
      <div>
        <label>Select</label>
        <select>
          <option>Option 1</option>
          <option>Option 2</option>
        </select>
      </div>
    </script>
    
    <script type="x-template" id="form-textarea">
      <div>
        <label>Textarea</label>
        <textarea></textarea>
      </div>
    </script>

    So instead of creating a new form-input component for each item in the fields array, I'm creating a new component that is associated with the correct component via the type property of the fields

    0 讨论(0)
  • 2021-02-02 02:02

    Based on the code from the answer, one could add dynamic content for each one of those form controls as well ( the full concept could be seen from the following site):

       Vue.component('form-input', {
      template: '#form-input'
      , props: ['label','cnt']
       });
    
    Vue.component('form-select', {
     template: '#form-select'
     , props: ['label','cnt']
    });
    
    Vue.component('form-textarea', {
       template: '#form-textarea'
       , props: ['label','cnt']
       });
    new Vue({
      el: '#app',
      data: {
        fields: [],
        count: 0
      }
      , mounted() {
        // fetch those from back-end
        this.addFormElement('form-input','lbl', "form-input-content")
        this.addFormElement('form-textarea','lbl', "form-textarea-content")
        var select_cnt = [
          {'value': 1, 'text': 'item-01'},
          {'value': 2, 'text': 'item-02'}
        ]
        this.addFormElement('form-select','some-label',select_cnt)
      }
      , methods: {
        addFormElement: function(type,label,cnt) {
         this.fields.push({
           'type': type
           , id: this.count++
           , 'label':label
           , 'cnt':cnt
         });
       }
      }
    })
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
    <div id="app">
     <component v-for="field in fields" v-bind:is="field.type" :key="field.id" :cnt="field.cnt" :label="field.label"></component>
    </div>
    
    <script type="x-template" id="form-input">
      <div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
    <label>{{label}}</label>
    <input type="text" :value="cnt"/>
      </div>
    </script>
    
    <script type="x-template" id="form-textarea">
      <div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
    <label>{{label}}</label>
    <textarea :value="cnt"></textarea>
      </div>
    </script>
    
    <script type="x-template" id="form-select">
      <div>
    <label>Select</label>
    <select>
      <option v-for="oitem in cnt" :value="oitem.value">{{oitem.text}}</option>
    </select>
      </div>
      <div v-html="cnt"></div>
    </script>

    0 讨论(0)
提交回复
热议问题