skip to Main Content

I have a vue3 project and I use the composition API.
I have a component which shows some items (called tokens in this case).

<script setup>
import { ref, onMounted, toRaw } from 'vue'
import RotaryToken from './RotaryToken.vue'

const tokens = ref([])

const addToken = () => {
  const id = new Date().valueOf()
  tokens.value.push({ id })
}

const removeToken = (id) => {
  console.log('id: ', id)
  tokens.value = tokens.value.filter((token) => {
    console.log('toRaw(token): ', toRaw(token))
    return token.id !== id
  })
  console.log('tokens.value: ', tokens.value)
}
</script>

<template>
  <div class="canvas">
    <div class="controls"><button @click="addToken">Add token</button></div>
    <div v-if="tokens.length <= 0" class="fallback-message">Place tokens here</div>
    <RotaryToken
      v-for="token in tokens"
      :key="token.id"
      @destroy="removeToken"
      :id="token.id"
    />
  </div>
</template>

The RotaryToken itself can emit a destroy event so I can remove itself from the array and therefore it should be removed. (I tried to self destroy a rotary token but no success).

Unfortunately I cannot remove a token from the reactive tokens array . The problem lies somewhere in Vues Reactivity stuff.

enter image description here

I can see that the id is the correct one but tokens.value.filter just does not work.
I tried with splicing instead of filtering, added nextTick. Nothing worked.

Maybe somebody has an idea how to remove a token from the array and make it therefore rerender the template and removing destroyed tokens?

2

Answers


  1. The problem is your filter test.

    tokens.value.filter((token) => {
        console.log('toRaw(token): ', toRaw(token))
        return token.id !== id
    })
    

    where you believe id is a number, but as your screenshot shows, it’s an object called "id" but also with an id property. So your filter test is only returning tokens where token.id !== object

    Either pass the actual id property to the function, or access the property on the object which would be id.id:

    tokens.value.filter((token) => {
        console.log('toRaw(token): ', toRaw(token))
        return token.id !== id.id
    })
    
    Login or Signup to reply.
  2. I’d suggest you change the remove implementation to benefit of vuejs reactivity in array :

    const removeToken = (id) => {
      console.log('id: ', id)
      // search index of the token to remove by its id
      const index = tokens.value.findIndex(token => token.id === id)
      if (index >= 0) {
        // index >= 0 -> index as been found in array -> use splice method to remove item in array
        tokens.value.splice(index, 1)
      }
      console.log('tokens.value: ', tokens.value)
    }
    

    This code should work if id is unique in tokens array.

    If it’s not the case, you could wrap the splice call in a while loop like this :

    const removeToken = (id) => {
      console.log('id: ', id)
      // search index of the token to remove by its id
      let index = tokens.value.findIndex(token => token.id === id)
      while (index >= 0) {
        // index >= 0 -> index as been found in array -> use splice method to remove item in array
        tokens.value.splice(index, 1)
        // and update the index var to search for a new token in the tokens array
        index = tokens.value.findIndex(token => token.id === id)
      }
      console.log('tokens.value: ', tokens.value)
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search