Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

splice not working properly my object list VueJs

I have a Object array but when i want remove a object from array list only items are deleted from the end

Html :

<div id="app">
  <table>
    <tr>
      <td><input type="text" name="test1" /></td>
      <td>
        <button class="btn" @click="addrow">add row</button>
      </td>
    </tr>
    <tr v-for="(row,index) in rows">
      <td><input type="text" name="test2" /></td>
      <td>
          <button class="btn" @click="removerows(index)">remove </button>
      </td>
    </tr>
  </table>
</div>

Js:

 new Vue({
        el: "#app",
        data: {
          counterrow:1,
            rows:[],
        },
        methods: {
            addrow:function(){
           this.rows.push({
                    id:this.counterrow
                });
          },
          removerows:function(index){
           this.rows.splice(index,1);
          },
        },
        });

Splice(index,1) not working correctly and just remove the last elements per delete , live demo : jsfiddle

like image 881
lock Avatar asked Jan 28 '18 09:01

lock


1 Answers

I think you probably missunderstand what is going on:

In VueJS there is a caching method which allow the reusing of existing component generated: - Each of your object are considered equals when rendered (at a DOM level).

So VueJS remove the last line because it is probably ask the least calculation and then recalcul the expected state. There are many side case to this (sometime, the local state is not recalculated). To avoir this: As recommended in the documentation, use :key to trace the id of your object. From the documentation:

When Vue is updating a list of elements rendered with v-for, by default it uses an “in-place patch” strategy. If the order of the data items has changed, instead of moving the DOM elements to match the order of the items, Vue will patch each element in-place and make sure it reflects what should be rendered at that particular index. This is similar to the behavior of track-by="$index" in Vue 1.x.

This default mode is efficient, but only suitable when your list render output does not rely on child component state or temporary DOM state (e.g. form input values).

To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key attribute for each item. An ideal value for key would be the unique id of each item. This special attribute is a rough equivalent to track-by in 1.x, but it works like an attribute, so you need to use v-bind to bind it to dynamic values...

temporary DOM state : Here it refer to your behaviour.

There is your corrected code (associated fiddle: https://jsfiddle.net/BenoitNgo/3Lrmswc5/):

HTML:

<div id="app">

<table>
<tr>
  <td><input type="text" name="test1" /></td>
  <td><button class="btn" @click="addrow">add row</button></td>
</tr>
<tr v-for="(row,index) in rows" :key="row.id">
  <td><input type="text" name="test2"/></td>
  <td><button class="btn" @click="removerows(index)" >remove </button></td>
</tr>
</table>
</div>

In your javascript:

new Vue({
            el: "#app",
            data: {
              counterrow:1,
                rows:[],
            },
            methods: {
                addrow:function(){
                  this.counterrow += 1;
                  this.rows.push({
                        id:this.counterrow,
                        model: ""
                    });
              },
              removerows:function(index){
               this.rows.splice(index,1);
              },
            },
            });

In this code:

  • I corrected the fact counterrow was never incremented
  • I added a :key

The doc of :key : https://vuejs.org/v2/guide/list.html#key

Here is another jsFiddle https://jsfiddle.net/BenoitNgo/2a1u1j2b/3/ with:

  • Adding a v-model
  • Displaying your data below your form
  • Corrected the fact counterrow was never incremented
  • Adding a :key
like image 75
Ngob Avatar answered Sep 28 '22 14:09

Ngob