Reputation: 8195
I am trying to create a Vue page that contains nested field collections. I.e. Parent form and repeatable child forms.
It works with the exception that when deleting a child form, the template renders incorrectly
Please see the fiddle example that I created - https://jsfiddle.net/c4marcus/1mu2oceb/8/
The sample data contains basic information for The Beatles. If you click the trash can next to "Ringo" then mistakenly "George" will disappear and not "Ringo".
However, when you click submit the correct data is being saved (see screenshot below).
I feel like the problem must lie with the MemberFormset
vue component's remove
method which is triggered by clicking the trash can button.
remove: function(index) {
this.members.splice(index, 1)
this.$emit('input', this.members)
},
Once spliced, the template should render the array of forms with the new data.
<div class="form-group" v-for="(member, index) in members">
<member-form :model="member"
:index="index"
@input="update(index, $event)">
<div slot="trash">
<button type="button"
class="btn btn-default margin-top-md"
@click="remove(index)">
<i class="fa fa-trash"></i>
</button>
</div>
</member-form>
<hr v-if="separator(index)" />
</div>
Upvotes: 2
Views: 465
Reputation: 82449
The main issue appears to be here:
<member-form :model="member"
:index="index"
@input="update(index, $event)">
You need to provide a key for the custom component included in your loop. In this case you are not directly iterating on the custom component, but providing a key to Vue helps it determine it's strategy to update the DOM. To that end I added an id
to each member
object
members: [
{name: 'John', id: 1},
{name: 'Ringo', id: 2},
{name: 'Paul', id: 3},
{name: 'George', id: 4}
]
and updated the template to this:
<member-form :model="member"
:index="index"
@input="update(index, $event)"
:key="member.id">
One more thing, as pointed out in the comments, your add method needs to be updated to add a new id
value.
add: function () {
const newId = Math.max(this.members.map(m => m.id)) + 1
this.members.push({name: null, id: newId})
},
Now your DOM is properly updated after a delete.
Here is the updated fiddle.
I noted a few things looking over some of the code that look like they fall into some Vue caveats. This code for example:
update: function(index, value) {
this.members[index] = value
this.$emit('input', this.members)
},
Looks like it would fall into Vue's array detection caveat. And althought it might not be causing issues right now, potentially might in the future.
Upvotes: 2