Reputation: 47
I'm making a simple todo list to learn Vue.
I am following this approach to add/remove an element from the list: Vue.js guide
When I remove an element from the array I would expect that element to disappear and then the other elements under it to take its space. But in my case the elements are shifted up and then the last element of the list (which has been "copied" one position up) is removed.
Problem: element removed correctly but transition wrong.
Reproducing problem: click remove on one of the items and look at the end of the list.
JSFiddle: link
HTML:
<div id="todoList">
<h1>todos </h1>
<input type="text" v-model="newItemText" class="new-todo" autofocus placeholder="What needs to be done?" @keyup.enter="addTodo">
<ul>
<transition-group name="list" >
<li v-for="(data, index) in todoList" v-bind:key="index">
{{data.text}}
<span class="remove-btn" v-on:click="removeItem(index)"> remove </span>
</li>
</transition-group>
</ul>
CSS:
<style>
.list-enter-active,
.list-leave-active {
transition: all 1s;
}
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
JS:
var app = new Vue({
el: "#todoList",
data: {
delete: '',
newItemText: '',
todoList: [
{text: '0'},
{text: '1'},
{text: '2'},
{text: '3'},
{text: '4'},
{text: '5'},
{text: '6'},
{text: '7'}
]
},
methods: {
addTodo: function(){
/* this.todoList.reverse(); */
if(this.newItemText != ''){
this.todoList.push({text: this.newItemText});
/* this.todoList.splice(0,0,{text: this.newItemText}); */
}
this.newItemText = '';
/* this.todoList.reverse(); */
},
removeItem: function(index) {
console.log(index);
this.todoList.splice(index, 1);
}
}
})
Upvotes: 3
Views: 702
Reputation: 29102
The problem is your choice of key
.
Vue uses the key
to determine which VNodes are equivalent from one render to the next. As you're using index
it pairs up the wrong nodes for the array entries and when there's no partner found for the final node it removes that.
So initially you have nodes with keys 0 to 7. You then remove the array item at index 4. But when Vue updates the rendering it doesn't see that 4 has been removed. It just sees nodes with keys 0 to 6. As far as it can tell it is the node with key 7 that has been removed.
For a quick experiment, try using :key="data.text"
. You'll see it now works but the text
isn't a great choice of key
as it isn't necessarily unique. You should probably add some sort of unique id to your array entries so you can use that instead.
Upvotes: 6