Dynamically adding different components in Vue
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
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>
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>