Search code examples
vue.jsarchitecturevuejs2

Vue.js 2 remove data (array item) from a corresponding component


enter image description here

I'm making a game.

  • A controller adds "coins" to the data.
  • When a coin is added, it mounts a component, which html gets animated (simple sprite animation with GSAP)
  • When the animation is over the coin needs to get deleted from the data.

This is where I struggle. I don't know how to delete the array-item from the data; does "mounted()" know about which array key?

I thought about passing the array-index to the component; the indizes constantly change; coins get added and deleted randomly.

I tried using splice() as suggested in here: How to remove a item from a array Vue.js, but couldn't get it to work.

Since I guess this is a pretty usual use-case I figured if there is a straight forward solution to this.

My html:

<div class="game">

    <xyz v-for="coin in coins" v-bind:data="coin" is="coin"></xyz>

</div>

My js:

// Simplified component
// of course the coin has data like value etc.
Vue.component("coin", {
    props: ["data"],

    template: `
        <div class="sprite">
            <img :src="coin' + data.lane . '.png" />
        </div>
    `,

    mounted () {
        // Sprite animation
        var TweenMax ...
        .eventCallback("onComplete", function() {

            // (!)
            // > delete the data entry, that triggered this rendering  
            // (!)

        })
    }
})

// Vue root instance 
var game = new Vue({
    el: ".game",

    data() {
        coins: [
            { lane: 3 },
            { lane: 2 },
            ...
        ]
    }
})

Solution

  • I think you'd better to delete a single coin from array at where coins are maintained(parent component). And in you child component(coin) just need to emit an event to tell the parent component that animation has already completed, please delete me.

    BTW, you could set an id for every coin then you can delete them from array by id very easily.

    Hope this would be helpful.

    // Simplified component
    // of course the coin has data like value etc.
    Vue.component("xyz", {
        props: ["data"],
    
        template: `
            <div class="sprite">
                <!-- <img :src="coin' + data.lane . '.png" /> -->
                <div>{{data.lane}}</div>
            </div>
        `,
    
        mounted () {
             setTimeout(()=>{
                this.$emit('completed', this.data);
             }, 2000);
        }
    })
    
    
    // Vue root instance 
    var game = new Vue({
        el: ".game",
    
        data() {
        return {
            coins: [
                { id: 1,
                lane: 3 },
                { id:2,
                lane: 2 },
            ]
          }
        },
        methods:{
            onCompleted(data){
              for(var c in this.coins){
                       if(this.coins[c].id === data.id){
                            this.coins.splice(c, 1);
                            break;
                       }
             }
              }
        }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
    <div class="game">
    
        <xyz v-for="coin in coins" v-bind:data="coin" :key="coin.id" @completed="onCompleted"></xyz>
    
    </div>