0

Here is what I have and I will explain it as much as I can:

  1. I have a modal inside my HTML code as shown below:

     <div id="favorites-modal-edit" class="modal">
         <div class="modal-background"></div>
         <div class="modal-card px-4">
             <header class="modal-card-head">
                 <p class="modal-card-title">Favorites</p>
                 <button class="delete" aria-label="close"></button>
             </header>
             <section class="modal-card-body">
                 <div class="container">
                     <div id="favorites-modal-edit-wrapper" class="columns is-multiline buttons">
                         <favorites-edit-component v-for="(favorite, index) in favorites_list" :key="favorite.id" :favorite="favorite" />
                     </div>
                 </div>
             </section>
             <footer class="modal-card-foot">
                 <button class="button" @click="addItem">
                     Add Item
                 </button>
             </footer>
         </div>
     </div>
    

The id="favorites-modal-edit" is the Vue.js app, then I have the <favorites-edit-component /> vue.js component.


Here is the JS code that I have:

I have my favorites_list generated which is an array of objects as shown below: enter image description here

const favorites_list = [
    {
        id: 1,
        name: 'Horse',
        url: 'www.example.com',
    },
    {
        id: 2,
        name: 'Sheep',
        url: 'www.example2.com',
    },
    {
        id: 3,
        name: 'Octopus',
        url: 'www.example2.com',
    },
    {
        id: 4,
        name: 'Deer',
        url: 'www.example2.com',
    },
    {
        id: 5,
        name: 'Hamster',
        url: 'www.example2.com',
    },
];

Then, I have my vue.js component, which is the favorites-edit-component that takes in the @click="removeItem(this.index) which is coming back as undefined on the index.

Vue.component('favorites-edit-component', {
   template: `
    <div class="column is-half">
      <button class="button is-fullwidth is-danger is-outlined mb-0">
        <span>{{ favorite.name }}</span>
        <span class="icon is-small favorite-delete" @click="removeItem(this.index)">
          <i class="fas fa-times"></i>
        </span>
      </button>
    </div>
   `,
    props: {
        favorite: Object
    },
    methods: {
       removeItem: function(index) {
           this.$parent.removeItem(index);
       },
    }
});

Then I have the vue.js app that is the parent as shown below:

new Vue({
    el: '#favorites-modal-edit',

    // Return the data in a function instead of a single object
    data: function() {
        return {
            favorites_list
        };
    },
    methods: {
        addItem: function() {
            console.log('Added item');
        },
        removeItem: function(index) {
            console.log(index);
            console.log(this.favorites_list);
            this.favorites_list.splice(this.favorites_list.indexOf(index), 1);
        },
    },
});

The problem:

For some reason, each time I go to delete a item from the list, it's deleting the last item in the list and I don't know why it's doing it, check out what is happening:

enter image description here

This is the guide that I am following:
How to remove an item from an array in Vue.js

The item keeps coming back as undefined each time the remoteItem() function is triggered as shown below:
enter image description here

All help is appreciated!

Daniel Beck
  • 20,653
  • 5
  • 38
  • 53

2 Answers2

1
  1. There is an error in your favorites-edit-component template, actually in vue template, when you want to use prop, data, computed, mehods,..., dont't use this => there is an error here: @click="removeItem(this.index)" => in addition, where is index declared ? data ? prop ?

  2. you're calling this.$parent.removeItem(index); then in removeItem you're doing this.favorites_list.splice(this.favorites_list.indexOf(index), 1); this means that you want to remove the value equal to index in you array no the value positioned at the index => this.favorites_list[index] != this.favorites_list[this.favorites_list.indexOf(index)]

In addition, I would suggest you to modify the favorites-edit-component component to use event so it can be more reusable:

favorites-edit-component:

<template>
  <div class="column is-half">
    <button class="button is-fullwidth is-danger is-outlined mb-0">
      <span>{{ favorite.name }}</span>
      <span class="icon is-small favorite-delete" @click="$emit('removeItem', favorite.id)">
        <i class="fas fa-times"></i>
      </span>
    </button>
  </div>
</template>

and in the parent component:

<template>
  ...
  <div id="favorites-modal-edit-wrapper" class="columns is-multiline buttons">
    <favorites-edit-component
      v-for="favorite in favorites_list"
      :key="favorite.id"
      :favorite="favorite"
      @removeItem="removeItem($event)"
    />
  </div>
  ...
</template>

<script>
export default {
  data: function () {
    return {
      favorites_list: [],
    };
  },
  methods: {
    ...
    removeItem(id) {
      this.favorites_list = this.favorites_list.filter((favorite) => favorite.id !== id);
    }
    ...
  },
};
David ROSEY
  • 1,414
  • 1
  • 7
  • 20
0

I would restructure your code a bit.

In your favorites-edit-component change your removeItem method to be

removeItem() {
  this.$emit('delete');
},

Then, where you are using your component (in the template of the parent) Add an event catcher to catch the emitted "delete" event from the child.

<favorites-edit-component v-for="(favorite, index) in favorites_list" :key="favorite.id" :favorite="favorite" @delete="removeItem(index)"/>

The problem you have right now, is that you are trying to refer to "this.index" inside your child component, but the child component does not know what index it is being rendered as, unless you specifically pass it down to the child as a prop.

Also, if you pass the index down as a prop, you must refer to it as "index" and not "this.index" while in the template.

Thomas Bay
  • 609
  • 4
  • 13
  • 1
    By the time I finished composing my answer, this answer had already been posted, which is basically the same as the one I posted then deleted. Doh! I do think you need to also pass the 'index' value (if it is defined) with the custom event: this.$emit('delete', index) – Tim Feb 03 '21 at 22:01
  • Thanks guys! This is much appreciated, I will test this later this evening and send all the upvotes and accepted answers as needed. –  Feb 03 '21 at 22:04
  • It is not neccessary to pass down the index in the solution i proposed :) Instead the component just emits "delete", and in the parent template the index is given as a parameter to the removeItem method, which is being called in the event catcher '@delete="removeItem(index)"' – Thomas Bay Feb 03 '21 at 22:05