Issue with Vue: After removing an item from a v-for list, there is a remnant

Can you help me solve this issue with my Vue component setup?

I have a list of components, each consisting of a preview canvas, a name, and a delete button. These components are stored in Vuex.

For example, the list could look like this:

| [W] Item 1      (Delete button) |
| [X] Item 2      (Delete button) |
| [Y] Item 3      (Delete button) |
| [Z] Item 4      (Delete button) |

The problem arises when an item is deleted from the list. Although the names update correctly, the previews remain in their original positions instead of reordering. So if we delete "Item 2" (preview X), the list will show:

| [W] Item 1      (Delete button) |
| [X] Item 3      (Delete button) |
| [Y] Item 4      (Delete button) |

The previews should rearrange to match the updated list after deletion.

Any suggestions for a solution that doesn't involve redrawing all the canvases?

Here's some relevant code snippets:

Clicking on the delete button triggers the deleteAsset method:

<button @click="deleteAsset">Delete</button>

deleteAsset(event){
    event.stopPropagation();
    this.isRenaming = false;
    this.$emit('deleteAsset', this.asset);
},

The emitted event is handled by a Vuex action:

deleteAsset(asset){
    this.$store.dispatch('GameData/deleteAsset', {category: asset.category_ID, id: asset.ID});
    this.updateAsset();
},

This action calls a mutation to remove the specified asset from the list:

//Action
deleteAsset({commit}, {category, id}){
    commit('deleteAsset', {category, id})
}

//Mutation
deleteAsset: (state, {category, id}) => {
    let curList = getList();
    let hasFound = false;

    for (let i = 0; !hasFound && i < curList.length; i++){
        if (curList[i].ID == id){
            curList.splice(i, 1);
            hasFound = true;
        }
    }
}

If you want to see the issue visually, here is a screenshot: https://i.sstatic.net/y6bSa.png

The rest of the data updates correctly upon deletion, but the canvas elements do not reflect the changes. I suspect it's an issue within the Vue component logic.

Here's the relevant Vue code for reference:

//List
<Asset
    ref="assets"
    v-for="asset in selectedList"
    :key="asset.cat_ID"
    :asset="asset"
    :defaultIcon="selected_category.icon"
    @deleteAsset="deleteAsset"
    @selectAsset="selectAsset"/>

//Asset code
<template>
    <div ref="asset" class="asset" :class="{selected : isSelected}" @click="selectAsset">
        <div class="leftFloat">
            <canvas v-show="hasThumb" class="thumbnail" ref="thumbNail" width="20" height="20">Test</canvas>
            <img v-if="!hasThumb" class="thumbnail assetIcon" :src="require(`@/${defaultIcon}.svg`)" />
            <div v-if="isRenaming">
                <input ref="renameText" v-model="asset.name" type="text" />
            </div>
            <div v-else>{{asset.name}}</div>
        </div>
        <div class="rightFloat">
            <button class="rightButton" @click="deleteAsset">
                <img class="rightIcon" src="@/assets/trash.svg" />
            </button>
        </div>
    </div>
</template>

Answer №1

When dealing with the cat_ID and multiple assets, it's crucial to avoid using it as a key in Vue. This is because Vue won't be able to track changes properly if the same cat_ID appears more than once in your selectedList.

Instead, utilize the ID property of your assets as the key:

<Asset
  ref="assets"
  v-for="asset in selectedList"
  :key="asset.ID"
  :asset="asset"
  :defaultIcon="selected_category.icon"
  @deleteAsset="deleteAsset"
  @selectAsset="selectAsset"/>

For more information on Vue keys, refer to key

The key attribute plays a crucial role in helping Vue's virtual DOM algorithm identify VNodes during list comparisons. It aids in efficiently handling element reordering and removal based on key presence.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best method for enclosing all text within an HTML document with a different element?

For example: FROM <div> whats up! <div> whats up2! </div> thank you for your help <div></div> </div> TO <div> <span>whats up!</span> <div><span> whats up2! </span&g ...

What methods can be utilized to enhance the visual appeal of a threejs model

I'm currently working on enhancing the visual quality of my 3D models, aiming for smoother edges and more realistic shadows. To achieve this, I am experimenting with an OBJ file format. Here's the code snippet I'm using to load and display t ...

Postponing the findings of a database for a quarter of an hour

Hey there, I'm a new coder and like to dabble in a bit of everything, so go easy on me! So, here's the deal: data from a poker tournament is constantly being updated in a database, but we're delaying the video feed by 20-25 minutes to preve ...

Axios failing to include Content-Type in header

I have set up an Odoo instance in the backend and developed a custom module that includes a web controller. Here is the code for the web controller: Web Controller # -*- coding: utf-8 -*- from odoo import http import odoo from odoo.http import Response, ...

Adding an active class to a selected list item can easily be accomplished by targeting the

Hey there, I'm attempting to apply a class to the selected list item and also add a class when scrolling to a specific div. For instance, if I scroll to div#six, the number six (6) in the menu should also have the 'active' class. [Check out ...

I am looking to insert an array of a specific type into a Postgres database using Node.js, but I am unsure of the process

query.callfunction('fn_create_mp_product', parameters, (err, result) => { if (err) { console.log(err) callback(err); } else { if (result.status == 'success') { callb ...

Updating the button text in Angular 7

Here's a question: <button (click)="activateMotion(1)"> <img class="emotion-icon" id="positive-icon" src="" /> </button> <button (click)="activateMotion(-1)"> <img class="emotion-icon" id="negative-icon" src="" /&g ...

The dynamically generated table will only show the most recently added data

Currently, I am delving into the world of JavaScript to tackle an interesting challenge. Here's the scenario: I have a dropdown list populated with stream names derived from an array. Whenever a selection in this array changes using `onchange()`, I wa ...

How to apply a series of spaces using span/tspan with jquery/javascript

Check out this fiddle: http://jsfiddle.net/jzLu4toe/3/ <span id='tghj'></span> $('#tghj').text('Hey There'); I'm facing an issue where I need to insert multiple spaces inside a span element. ...

Is there a way to open an image.png file in typescript using the "rb" mode?

Is there a way to open png files in typescript similar to the python method with open(path+im,"rb") as f:? I have a folder with png files and I need to read and convert them to base 64. Can anyone assist me with the equivalent method in typescript? This i ...

Resize the shape of an image's polygon

Is there a way to independently scale a specific polygon of an image on hover? For example, I have a world map and I would like to enlarge a country when hovering over it, then return it to its original size when no longer hovering. I am familiar with us ...

I keep encountering an error that says "ReferenceError: localStorage is not defined" even though I have already included the "use

I have a unique app/components/organisms/Cookies.tsx modal window component that I integrate into my app/page.tsx. Despite including the 'use client' directive at the beginning of the component, I consistently encounter this error: ReferenceErr ...

Looking for a resolution with NicEditor - Seeking advice on incorporating custom select options

I recently started using NICInline Editor and found a helpful sample at Is there a way to incorporate custom options into this editor? I would like the selected option's value to be inserted right at the cursor point of the Editor Instance. Query: H ...

Creating Virtual Nodes from a string with HTML tags in Vue 2.5: A Step-by-Step Guide

Having some trouble creating a functional component that displays the Feather Icons package - I'm stuck on the final step. Here's what I have so far: This is my FeatherIcon.vue component. <script> const feather = require("feather-icons"); ...

on clicking GTM, obtain a different child element

My HTML code is structured as follows: <div onclick="location.href='https://ford-parts-accessories.myshopify.com/products/ash-cup-coin-holder-with-lighter-element?refSrc=6748959244479&amp;nosto=productpage-nosto-1-fallback-nosto-1';&q ...

Expand and collapse dynamically while scrolling

// Closing Button for Main Navigation $('button#collapse-button').click(function () { $('nav#main-nav').toggleClass('closed'); }); $(window).on('scroll', function () { if ($(wind ...

What is the reason behind Vue's inability to detect the data member when it is used in the v-html attribute

Having created a reusable Vue component, my code looks like this: Vue.component('ValueDisplay', { template: '<div v-html="value"></div>', data: function () { value: '' }, mounted: ...

Managing failures in dynamic imports within vue applications

I am facing the challenge of importing custom components to override standard ones. These custom components are loaded using an environment variable that points to a selected custom folder containing the client’s unique components. However, I am struggli ...

Alter the class of the div element every three seconds

Greetings, I trust everyone is doing well. I am in need of some assistance from your brilliant minds. I have a circular div along with three CSS classes, and my objective is to switch the div's class and update the label text every 3 seconds. Any insi ...

Display only alphabetic characters in the text field

I have a jQuery function that I am working on: $('#contact_name').on('input', function() { var input=$(this); var re =/^[A-Za-z]+$/; var is_email=re.test(input.val()); if(is_email) { } else { } }); This function is targeted at the fol ...