0

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 },
            ...
        ]
    }
})
katerlouis
  • 536
  • 6
  • 16
  • Please aslo provide any fiddle/live demo ? – Niklesh Raut Apr 16 '18 at 10:14
  • Hard to extract this out of the full project, which obviously isn't working and has way more data etc. pp. – What exactly don't you understand? I basically need to delete the object in the main app's `data.coins`-array, that triggered the `mounted()` function of the component. But I can't get `mounted()` to know about it's corresponding array-item. – katerlouis Apr 16 '18 at 10:26
  • Do you have any git repo of this? – Niklesh Raut Apr 16 '18 at 10:48

1 Answers1

1

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>
tony19
  • 125,647
  • 18
  • 229
  • 307
Kevin Law
  • 814
  • 4
  • 15
  • What you describe in your first sentence is exactly what I'm trying to do, but I don't know how. Could you update your answer with a code example of how you would emit the event? – katerlouis Apr 16 '18 at 10:31
  • I thought about the id aswell, but don't know a convenient way creat unique IDs, unless add a counter to the main app, which would clutter everything even more. Maybe, just for learning purposes, you could illustrate that solution aswell? Thank you! – katerlouis Apr 16 '18 at 10:33
  • I've updated my answer with code snippet, as well the id solution. – Kevin Law Apr 16 '18 at 11:09
  • Thank you! Still got questions, though: 1) Is there a reason why you changed my image to `
    {{ data.lane }}
    `? 2) You talked about 2 solutions, the code example covers just the ID way, right? 3) how would you add coins and ensure that the ID is unique? 4) why do you have to do `@completed="onCompleted"`? Couldn't you just $emit to onCompleted directly?
    – katerlouis Apr 16 '18 at 12:25
  • 1
    1. You can ignore it, I was just trying to display something. Image will broken as I don't have those images. 2. Yes, also you can save an index to a local variable when adding it. 3. There are many ways to achieve that, for example you can use some 3rd party library likes [uuid](https://github.com/kelektiv/node-uuid) to generate a unique id or even simply use current Unix timestamp as a unique id. 4. **emit** is fire the event in child component while **@completed="onCompleted"** is bind a event handler for parent component. This is the stand way communicate from child component to parent. – Kevin Law Apr 16 '18 at 16:45
  • Thank you very much! Especially for the timestamp tip; that's awesome– I somewhat hoped I could avoid the use of a uid and that Vue can take care of this itself under the hood :D – katerlouis Apr 16 '18 at 17:28
  • One more thing: the arrow funciton in the filter is a new ES6 function, right? So it won't work in IE11, right? – katerlouis Apr 16 '18 at 17:48
  • Yes, it came with ES6 and not supported by all IE version, you can change it to normal function. For browser support, [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) document has a detail list. – Kevin Law Apr 17 '18 at 02:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/169147/discussion-between-kater-louis-and-kevin-law). – katerlouis Apr 17 '18 at 09:06
  • The vue chat gladly helped me solve the issue; apparently you have to add `:key="coin.id` to the `v-for`-loop. https://vuejs.org/v2/guide/list.html#key Could you please update your answer? – katerlouis Apr 18 '18 at 09:25