Asked By: Anonymous
I have read the documentation for rendering the custom components in list using v-for here.
But for some reason, I am not able to get this working.It always delete the last component instead of the one I send in the index. Any idea why it is not working ?
My VUE JS version is : 2.5.16.
Using PHPStorm IDE and running on docker (linux container)
And Laravel mix (I have “laravel-mix”: “0.*” entry in package.json) to use webpack and compile the JS modules.
Here is the piece of some of my code
// Parent Component JS
<template>
<ul>
<li
is="child-component"
v-for="(child, index) in componentList"
:key="index"
:myVal="Something...."
@remove="dropField(index)"
@add-custom-field="addField"
></li>
</ul>
</template>
<script>
import childComponent from './ChildComponent';
export default {
name: 'CustomList',
components: {'child-component' :childComponent},
data() {
return {
componentList: []
}
},
methods: {
addField() {
console.log('Handling add-custom-field field...');
this.componentList.push(childComponent);
},
dropField(index) {
console.log(`I am deleting the component with index = ${index} from listview in parent...`);
this.componentList.splice(index, 1);
}
}
}
// Child Component JS
<template>
<div>
<input type="text" v-model="currentValue" /><button @click.prevent="$emit('remove')" > Remove </button>
</div
</template>
<script>
export default {
props: { myVal : '' },
data() { return { currentValue: ''} },
created() {this.currentValue = this.myVal;}
}
</script>
Solution
Answered By: Anonymous
The issue is caused by in-place patch†strategy for v-for. That means Vue will not rebuild all childs when removed one element from componentList.
Check Vue Guide on an “in-place patch†strategy for v-for:
When Vue is updating a list of elements rendered with v-for, by
default it uses an “in-place patch†strategy. If the order of the data
items has changed, instead of moving the DOM elements to match the
order of the items, Vue will patch each element in-place and make sure
it reflects what should be rendered at that particular index.
Actually you already deleted the last item, but the problem is the data property=currentValue of first&second child have been ‘a’, ‘b’, when first mounted. Later when Vue re-render (delete the last child), data property=currentValue keeps same value though prop=myVal already changed.
Look at below demo, I added one input and bind myVal, you will see the differences.
Vue.config.productionTip = false_x000D_
_x000D_
let childComponent = Vue.component('child', {_x000D_
template: `<div class="item">_x000D_
<p>Index:{{parentIndex}} => <button @click.prevent="removed()" > Remove </button>_x000D_
Data:<input type="text" v-model="currentValue" />Props:<input type="text" v-bind:value="myVal" />_x000D_
</p> _x000D_
</div>`,_x000D_
props: { 'myVal':{_x000D_
type: String,_x000D_
default: ''_x000D_
} ,_x000D_
'parentIndex': {_x000D_
type: Number,_x000D_
default: 0_x000D_
}_x000D_
},_x000D_
data() {_x000D_
return { _x000D_
currentValue: ''_x000D_
} _x000D_
},_x000D_
mounted() {_x000D_
this.currentValue = this.myVal_x000D_
},_x000D_
methods: {_x000D_
removed: function () {_x000D_
this.$emit('remove')_x000D_
}_x000D_
}_x000D_
})_x000D_
_x000D_
_x000D_
app = new Vue({_x000D_
el: "#app",_x000D_
data() {_x000D_
return {_x000D_
componentList: ['a', 'b', 'c'],_x000D_
componentType:childComponent_x000D_
}_x000D_
},_x000D_
_x000D_
methods: {_x000D_
addField() {_x000D_
console.log('Handling add-custom-field field...');_x000D_
this.componentList.push(childComponent);_x000D_
},_x000D_
_x000D_
dropField(index) {_x000D_
console.log(`I am deleting the component with index = ${index} from listview in parent...`);_x000D_
this.componentList.splice(index, 1); _x000D_
}_x000D_
}_x000D_
})
_x000D_
li:nth-child(odd) {_x000D_
background-color:#d0d5dd;_x000D_
}
_x000D_
<a href="https://unpkg.com/[email protected]/dist/vue.js">https://unpkg.com/[email protected]/dist/vue.js</a>_x000D_
<div id="app">_x000D_
<ul>_x000D_
<li v-for="(child, index) in componentList"><div_x000D_
:is="componentType"_x000D_
:key="index"_x000D_
:my-val="child"_x000D_
:parent-index="index"_x000D_
@remove="dropField(index)"_x000D_
@add-custom-field="addField"_x000D_
>{{child}}</div></li>_x000D_
</ul>_x000D_
</div>
_x000D_
_x000D_
x000D