Search code examples
javascripthtmlvue.jsgrid-layoutvue-dynamic-components

Remove ANY Grid-Item on the click of an 'x' button that is within each item, my method only deletes the last one


I am re-vamping a program for my Engineering departments research team, my app has been built using Electron, Vuex, HTML/Sass/Javascript. The program's purpose is to allow the user to create "steps" which are items/tiles that you can go into & set system parameters & processes to run X amount of times. Setting up the values and settings within each step can take a while, so if the user creates 5 steps, and realizes they want to delete step number 2 entirely, there needs to be a 'remove' or a small 'x' within each step/item. Currently, I can only remove the last populated step/item using the 'pop' function to remove the last item in the array 'stepsGrid'.

Using vue-grid-layout to populate grid-items/tiles which will each be a 'step' that our system will run. I am able to dynamically add new 'steps', however I have only been able to successfully remove steps by using pop() to remove the last item from the array in which grid-items are. I want to place a

<button id="remove" @click="removeStep()">Remove</button>

within each step, so that I can delete any item on the grid instead of just the last item.

I have seen a few examples, but not being the best at javascript- I haven't had any luck. I tried referencing the functions used here: https://chrishamm.io/grid-demo/ and https://github.com/chrishamm/vue-dynamic-grid for removing grid items, however this library is a little more complicated than the regular Vue-Grid-Layout.

Here is my code, the key is the step.i component which is the ID of each item populated, each tile will have an 'x' in the corner and the function needs to be able to recognize the ID of that tile, and delete the corresponding item from the stepsGrid array:

<h2 style="color: #f6a821;">Steps</h2>
<hr class="hr" />
<grid-layout
  :layout.sync="stepsGrid"
  :col-num="8"
  :row-height="75"
  :is-draggable="true"
  :is-resizable="false"
  :is-mirrored="false"
  :vertical-compact="true"
  :margin="[50, 50]"
  :use-css-transforms="true">

<grid-item
  v-for="step in stepsGrid" :key= "step.i"
  :x="step.x"
  :y="step.y"
  :w="step.w"
  :h="step.h"
  :i="step.i"
  :isDraggable="step.isDraggable">

<div class="Panel__name">Step: {{step.i}} //displays item # on each tile
<div class="Panel__stepcount"> Loop Count: <input type="number" value="1">
 </div>
</div>
<div class="editButton">
<div class="Panel__status">Status:</div>
<button @click="removeStep()">Remove</button>


</grid-item>
</grid-layout>

//Grid arrays are in store.js, as shown below(this is for an electron app):

import Vue from 'vue';
import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex);

export const store = new Vuex.Store({
state: {
 stepsGrid : [
{"x":0,"y":0,"w":2,"h":1,"i":"0"}
],

mutations: {
addStep (state, step){
state.stepsGrid.push(step);
}
},

actions: {
  addStep ({state, commit}){
    const step = 
    {"x":0, "y": 1, "w": 2,"h":1,"i":String(state.stepsGrid.length) };
    commit('addStep', step);
 },

I know I need to incorporate the use of a key here, but I am unsure how to do it. I found this, but he goes about it an unusual way:

"I deleted the element in array by the button and could not understand the problem, as the last element was always deleted, although the key was unique. I added an extra unique uuid and it all worked."

<dish-item v-else class="dishItem" 
v-for="(item, key) in dishes" :key="key + $uuid.v1()" :value="item"
@removeDish="$delete(dishes, key)" 
@editDish="$refs.modal.showEdit({item, key})"
/>

Lastly, I went digging through the files for Vue-Dynamic-Grid and found that they are removing items with the following method:

methods: {
    removeElement(item) {
    if (item == this.selectedItem) {
    this.selectElement(null);
}

this.gridItems.splice(item.i, 1);
this.items.splice(item.i, 1);
breakpoints.forEach(function(size) {
    this.layouts[size].splice(item.i, 1);
    this.layouts[size].forEach(function(layout, i) {
       if (layout.i > item.i) {
         layout.i--;
        }
    });
}, this);
this.$emit("itemRemoved", item);
    }

If anyone could be of help, I would appreciate it! I have been learning JS on the go with this project, so if anyone has some tips please let me know! Thanks

I have tried attempting to write a function based on the way Vue-Dynamic-Layout's method for removing items, but I was not successful. As of right now, I don't have a small 'x' in each tile, I have a button for adding/removing a step in the bottom left of my app, to remove items I am simply popping the last item out of the stepsGrid array, so I can only remove the last populated item.


Solution

  • First let the event handler know which step is being clicked

    <button @click="removeStep(step)">Remove</button>
    

    Then find that step in the array and remove it

    methods: {
        removeStep(step) {
            const index = this.stepsGrid.indexOf(step);
            if (index >= 0) this.stepsGrid.splice(index, 1);
        }
    }