Search code examples
listvue.jsvuejs2v-for

Displaying(adding, editing) and Deleting list items in multiple columns in Vue.js without v-if and v-for


I am beginner in Vue.js. I want to add new items in list, but these items need to be displayed in separate divs according to their "category" property. Also, every item has option to be edited (haven't made that yet) or deleted. I have read that it is not recommended to use v-if inside v-for, so inspired by second answer here I used Computed Properties to do that. I needed to add index for every list item, because I haven't found any way to delete list item in Vue.js without index. The problem is that we iterate over two lists from computed properties and basically we have repeating indexes (check out print of list items in my code and you will understand) so it deletes items from wrong category. This problem would make editing item names harder, too.
I was thinking of way to solve this, but I would have to use v-for and v-if together which is not recommended.
Also, this is not very good solution for me, because I would probably need to generate these divs dynamically from given list of categories (there could be a lot of them), and I don't know how would I be able to generate computed properties dynamically for each category. For this I would need to use v-if inside v-for, which is not recommended.

So basically I have two problems:
1. Deleting items from wrong category
2. Dynamically generating divs for each category if I keep using this method with computed properties.

Here is my code: fiddle
Do you have any advice or solutions?
Thanks in advance!


Solution

  • The index in the v-for has nothing to do with that of the object in the amenities array.

    Since you don't want to make one loop for both categories, I can this solution:

    A better approach would be to autogenerate a unique id for each object on addition, and then deleting according to it:

    new Vue({
        el: '#app',
      data: function() {
        return {
          Amenity: {
            name: '',
            category: ''
          },
          amenities: [],
          nextId:0
        }
      },
      computed: {
        familyCategory: function () {
            return this.amenities.filter(i => i.category === 'family')
        },
        facilitiesCategory: function () {
            return this.amenities.filter(i => i.category === 'facilities')
        }
      },
      methods: {
        addAmenity: function(e) {
          this.amenities.push({
            id: this.nextId,
            name: this.Amenity.name,
            category: this.Amenity.category
          });
          this.Amenity = {
            name: '',
            category: 'family'
          };
          this.nextId = this.nextId+1;
        },
        
       removeElement : function (id) {
          console.log(id);
          this.amenities=this.amenities.filter(e => e.id!=id);
        }
      }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
    <div id="app">
      <br /> Amenity name:
      <input type="text" v-model="Amenity.name" placeholder="Amenity name">
      <label for="category">Category:</label>
      <select id="cetegory" v-model="Amenity.category">
        <option value="family">Family</option>
        <option value="facilities" >Facilities</option>
      </select>
      
      
      <input type="button" @click="addAmenity" value="Submit" class="btn btn-info">
    
      <div>
      <h3>Family</h3>
        <ol>
          <li v-for="(item, index) in familyCategory">
            {{ index }} - {{ item.name }}
            <button>
              Edit
            </button>
            <button v-on:click="removeElement(item.id)">
               Delete
            </button>
          </li>
        </ol>
      </div>
      
      <div>
        <h3>Facilities</h3>
        <ol>
         <li v-for="(item, index) in facilitiesCategory">
            {{ index }} - {{ item.name }}
            <button>
              Edit
            </button>
            <button v-on:click="removeElement(item.id)">
               Delete
            </button>
            </li>
        </ol>
      </div>
    </div>