Search code examples
javascriptvue.jssplice

splice always delete last item in Vue.js


I'm sure the problem is very simple, but I have stack in it for hours.

I created an app that can add or remove to upload files.

When I click delete button, it always delete the last items. I have tried to solve it by adding :key="key", and it changes nothing.

What may be wrong with my code? Here is the codepen: https://codepen.io/shanyulin/pen/RwaWaZy?editors=1010

HTML

<div id="app">
  <div class="form-group clearfix" v-for="(event, key) in events" v-bind:key="key">
  <input name="attachment[]" accept="image/png, image/jpeg, application/pdf" type="file" class="form-control form-control-lg">
  <button @click="deleteEvent(key)" class="btn btn-danger">x</button>
</div>
<button @click="addEvent" class="btn btn-dark">+</button>
</div>

Js

const app = new Vue({
    el: '#app',
    data() {
        return {
            events: [{}],
           }
    },
    methods: {
        addEvent: function() {
            let quantity = this.events.length;
            if (quantity < 6) {
                this.events.push({
                    index: ''
                });
            } else {
                return false;
            }
        },
        deleteEvent: function(key) {
            let quantity = this.events.length;
            if (quantity == 1) {
                alert("Please upload at least one file.");
            }
            if (quantity > 1) {
                const confirmed = confirm("Do you really want to delete?");
                if (confirmed) {
                    this.events.splice(key, 1);
                }
            }
        }
    },
});

Solution

  • Array index is not reliable for key. If you have an array with three elements, keys are 0,1,2. When you remove second one, keys are 0,1, not 0,2.

    You need to provide unique key for each element.

    const app = new Vue({
        el: '#app',
        data() {
            return {
                events: [{}],
                uniqueKey: 0,
               }
        },
        methods: {
            addEvent: function() {
                let quantity = this.events.length;
                if (quantity < 6) {
                    this.events.push({
                        index: '',
                        key: this.uniqueKey++
                    });
                } else {
                    return false;
                }
            },
            deleteEvent: function(key) {
                let quantity = this.events.length;
                if (quantity == 1) {
                    alert("Please upload at least one file.");
                }
                if (quantity > 1) {
                    const confirmed = confirm("Do you really want to delete?");
                    if (confirmed) {
                        this.events.splice(key, 1);
                    }
                }
            }
        },
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    
    <div id="app">
      <div class="form-group clearfix" v-for="(event, key) in events" v-bind:key="event.key">
      <input name="attachment[]" accept="image/png, image/jpeg, application/pdf" type="file" class="form-control form-control-lg">
      <button @click="deleteEvent(key)" class="btn btn-danger">x</button>
    </div>
    <button @click="addEvent" class="btn btn-dark">+</button>
    </div>