Reputation: 6169
I followed the solution to create dynamic form elements here: Dynamically adding different components in Vue
Works great, my next conundrum is now I want to remove form elements if the user adds too many.
The way it works is the user creates a "set" which is defined as a group of inputs. So each set could be for a different person, or place, etc.
Here is my JSfiddle https://jsfiddle.net/61x784uv/
Html
<div id="component-pii-input" v-for="field in fields" v-bind:is="field.type" :key="field.id">
</div>
<button id='button-add-pii-component' v-on:click="addFormElement('pii-entry-field')">Add Set</button>
</div>
Javascript
Vue.component('pii-entry-field', {
data: function () {
return {
fields: [],
count: 0,
}
},
methods: {
addFormElement: function(type) {
this.fields.push({
'type': type,
id: this.count++
});
},
},
template: ` <div class='pii-field'><div>
<component v-for="field in fields" v-bind:is="field.type":key="field.id"></component>
</div>
<button id='button-add-pii-input' v-on:click="addFormElement('pii-input-field')">Add Input</button>
<hr>
</div>`,
})
Vue.component('pii-input-field', {
data: function () {
return {
}
},
template: ` <div>
<select>
<option disabled>Select Classification</option>
<option>Name</option>
<option>Address</option>
<option>Email</option>
<option>Phone</option>
<option>Medical</option>
<option>Financial</option>
</select>
<div>
<input type="text" placeholder="Input">
</div>
<button v-on:click="removeFormElement">Remove Input</button></span>
</div>`,
})
var app = new Vue({
el: '#app',
data: {
fields: [],
count: 0,
},
methods: {
addFormElement: function(type) {
this.fields.push({
'type': type,
id: this.count++
});
},
}
});
Upvotes: 1
Views: 11321
Reputation: 4057
Here is a working fiddle: https://jsfiddle.net/e12hbLcr/
Walkthrough:
You need to give the component some kind of id to know what component should be removed. You can do this with props.
<component v-for="field in fields" v-bind:is="field.type" :id="field.id" :key="field.id">
Now create the function in the child-component and edit the button so it sends the id.
<button v-on:click="removeFormElement(id)">Remove Input</button>
Remember in Vue that props go down (parent -> child) and events up (child-parent). So now we need to tell the parent that this button was clicked and an id was sent.
removeFormElement(id) {
console.log('sending message up to remove id', id)
this.$emit('remove', id)
}
Tell the parent component to listen to that event and attach a function to that event.
<component v-for="field in fields" v-bind:is="field.type" :id="field.id" @remove="removeFormElement" :key="field.id">
Note that the @ is same as v-on:
removeFormElement(id) { console.log('removing form element', id) const index = this.fields.findIndex(f => f.id === id) this.fields.splice(index,1) }
Upvotes: 6
Reputation: 9180
You should probably move these remove buttons into a <slot>
of the component so you could pass in the scoped id
.
But if you can't, you could $emit
removal event on the $parent
of the individual components, passing the id
of the item to remove.
Vue.component('pii-entry-field', {
data() {
return {
fields: [],
count: 0,
}
},
mounted() {
this.$on('removeFormElement', this.removeFormElement);
},
methods: {
addFormElement(type) {
this.fields.push({
'type': type,
id: this.count++
});
},
removeFormElement(id) {
const index = this.fields.findIndex(f => f.id === id);
this.fields.splice(index, 1);
}
},
template: `
<div class='pii-field'>
<component v-for="field in fields" v-bind:is="field.type" :key="field.id"></component>
<button id='button-add-pii-input' v-on:click="addFormElement('pii-input-field')">Add Input</button>
<hr>
</div>`,
})
Vue.component('pii-input-field', {
data() {
return {
}
},
methods: {
removeFormElement() {
const id = this.$vnode.key;
this.$parent.$emit('removeFormElement', id);
}
},
template: `
<div>
<select>
<option disabled>Select Classification</option>
<option>Name</option>
<option>Address</option>
<option>Email</option>
<option>Phone</option>
<option>Medical</option>
<option>Financial</option>
</select>
<div>
<input type="text" placeholder="Input" />
</div>
<button v-on:click="removeFormElement">Remove Input</button>
</div>`,
})
var app = new Vue({
el: '#app',
data() {
return {
fields: [],
count: 0,
}
},
methods: {
addFormElement(type) {
this.fields.push({
'type': type,
id: this.count++
});
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="component-pii-input" v-for="field in fields" v-bind:is="field.type" :key="field.id">
</div>
<button id="button-add-pii-component" v-on:click="addFormElement('pii-entry-field')" class="uk-button uk-button-primary uk-width-1-1 uk-margin-small">Add Set</button>
</div>
Upvotes: 1