7

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

4
  • where does index come from in the click event? Commented Jan 28, 2018 at 9:11
  • index from array list (rows), when fetch array get it (row,index) and send to remove function Commented Jan 28, 2018 at 9:15
  • it actually works, you just can't tell because your html reflects only the iteration counter, not any data. if you inject something from the data, it looks fine: jsfiddle.net/duej8L3c ... Commented Jan 28, 2018 at 9:37
  • Thanks a lot,that's work, Is there another way not inject value to input's ? (my inputs have dynamic name and id ) Commented Jan 28, 2018 at 9:47

1 Answer 1

16

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://v2.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
Sign up to request clarification or add additional context in comments.

4 Comments

i noticed it also lost form input values entered by the user, is that normal?
Test this code, the input value entered by the user is no longer lost. I will update with a more complete fiddle
Thanks! This ruined my time like "What is going on!" before researching it was the key i omitted hoping to put it after i finished with it
"In VueJS there is a caching method which allow the reusing of existing component generated" I have been wracking my brain against this for hours. Doing prototyping at the moment and simply splicing out one object for another and not getting an update. Turns out it is because it generates the same key in the bindings! You are my hero for today!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.