Vue cannot detect the changes to the array when you set at an index outside the initial length of the array. Particularly Vue 2 can be fickle with reactivity.
A simple fix is to just push the index (or the item) into the array, and then check with includes()
.
In your methods:
methods: {
editItem(item) {
this.editing.push(item)
},
saveItem(item) {
this.editing = this.editing.filter(i => i !== item)
},
},
In the template:
<span v-show="!editing.includes(item)">
<button class="icon-A" @click="() => editItem(item)">A</button>
</span>
<span v-show="editing.includes(item)">
<button class="icon-B" @click="() => saveItem(item)">B</button>
</span>
See it running in the snippet:
new Vue({
el: '#app',
data() {
return {
items: [
{ id: 1, columnA: 'A1', columnB: 'B1' },
{ id: 2, columnA: 'A2', columnB: 'B2' },
{ id: 3, columnA: 'A3', columnB: 'B3' },
],
editing: [],
};
},
methods: {
editItem(item) {
this.editing.push(item)
console.log("editItem")
},
saveItem(item) {
this.editing = this.editing.filter(i => i !== item)
console.log("saveItem")
},
},
})
<div id="app">
<table>
<thead>
<tr>
<th>Column A</th>
<th>Column B</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in items" :key="item.id">
<td>{{ item.columnA }}</td>
<td>{{ item.columnB }}</td>
<td>
<span v-show="!editing.includes(item)">
<button class="icon-A" @click="() => editItem(item)">A</button>
</span>
<span v-show="editing.includes(item)">
<button class="icon-B" @click="() => saveItem(item)">B</button>
</span>
</td>
</tr>
</tbody>
</table>
<div> Editing: {{editing}} </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.10/vue.min.js"></script>
If you want to avoid the overhead of include()
in favor of a lookup, you can use an object and Vue.set()
/Vue.delete()
:
data() {
return {
...
editing: {},
};
},
methods: {
editItem(index, item) {
Vue.set(this.editing, index, item)
},
saveItem(index, item) {
Vue.delete(this.editing, index)
},
},
})
new Vue({
el: '#app',
data() {
return {
items: [
{ id: 1, columnA: 'A1', columnB: 'B1' },
{ id: 2, columnA: 'A2', columnB: 'B2' },
{ id: 3, columnA: 'A3', columnB: 'B3' },
],
editing: {},
};
},
methods: {
editItem(index, item) {
Vue.set(this.editing, index, item)
console.log("editItem")
},
saveItem(index, item) {
Vue.delete(this.editing, index)
console.log("saveItem")
},
},
})
<div id="app">
<table>
<thead>
<tr>
<th>Column A</th>
<th>Column B</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in items" :key="item.id">
<td>{{ item.columnA }}</td>
<td>{{ item.columnB }}</td>
<td>
<span v-show="!editing[index]">
<button class="icon-A" @click="() => editItem(index, item)">A</button>
</span>
<span v-show="editing[index]">
<button class="icon-B" @click="() => saveItem(index, item)">B</button>
</span>
</td>
</tr>
</tbody>
</table>
<div> Editing: {{editing}} </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.10/vue.min.js"></script>