user1830108
user1830108

Reputation: 193

issue caused the Row selection overwrite

I asked question on adding/removing row in how to use "v-for" for adding or removing a row with multiple components

However, I got a bug: when I adding a row, the items in the first row filled to second row and when I changed the second row, the 1st row is also overwritten as the same as 2nd row.

i must did sth really wrong.

in .js

 var data1={selected: null, items: ["A1","B1"]};
 Vue.component('comp1',{
       template: ` <select v-model="selected">
           <option disabled value="">Please select</option>
           <option v-for="item  in items" :value="item">{{item}}
            </option>
           </select>`,
      data:function(){
         return data1
         }         
     });

    var data2={selected: null, items: ["A2","B2"]};
    Vue.component('comp2',{
        template: ` <select v-model="selected">
                     <option disabled value="">Please select</option>
                     <option v-for="item in items" :value="item">{{item}}
            </option>
             </select>`,
           data:function(){
           return data2
            }          
          });




new Vue({
  el: '#app',
  data: {
    rows: []
  },
  computed:{
    newId(){
     return this.rows.length == 0 ? 1 : Math.max(...this.rows.map(r => r.id)) + 1
    }
  },
  methods: {
    addRow: function() {
      this.rows.push({id: this.newId });
    },
    removeRow: function(row) {
       this.rows.splice(this.rows.indexOf(row), 1)
    }
  },

});

in .html

<div id="app">
  <div v-for="row in rows">
    <comp1></comp1>
    <comp2></comp2>

    <button @click="removeRow(row)">Remove Row</button>
  </div>
  <button @click="addRow">Add Row</button>
</div>

Upvotes: 0

Views: 50

Answers (1)

Bert
Bert

Reputation: 82489

You need to add the key.

<div v-for="row in rows" :key="row.id">

And you shouldn't share the data between the components, so move your data into the components.

data: function() {
  return {
    selected: null,
    items: ["A1", "B1"]
  }
}

Here is a working version.

Vue.component('comp1', {
  template: ` <select v-model="selected">
           <option disabled value="">Please select</option>
           <option v-for="item  in items" :value="item">{{item}}
            </option>
           </select>`,
  data: function() {
    return {
      selected: null,
      items: ["A1", "B1"]
    }
  }
});

Vue.component('comp2', {
  template: ` <select v-model="selected">
                     <option disabled value="">Please select</option>
                     <option v-for="item in items" :value="item">{{item}}
            </option>
             </select>`,
  data: function() {
    return {
      selected: null,
      items: ["A2", "B2"]
    }
  }
});




new Vue({
  el: '#app',
  data: {
    rows: []
  },
  computed: {
    newId() {
      return this.rows.length == 0 ? 1 : Math.max(...this.rows.map(r => r.id)) + 1
    }
  },
  methods: {
    addRow: function() {
      this.rows.push({
        id: this.newId
      });
    },
    removeRow: function(row) {
      this.rows.splice(this.rows.indexOf(row), 1)
    }
  },

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
  <div v-for="row in rows" :key="row.id">
    <comp1></comp1>
    <comp2></comp2>

    <button @click="removeRow(row)">Remove Row</button>
  </div>
  <button @click="addRow">Add Row</button>
</div>

Specifically, the way you are sharing data is because you are defining the data like this:

var data1={selected: null, items: ["A1","B1"]};

And returning that object from your data function in the component:

data:function(){
  return data1
}         

This means that every instance of that component is sharing the same data. That's not what you want with components. Each component should have it's own copy of the data. In this case, there is no need whatsoever to define the data object returned from the data function outside the component.

Upvotes: 1

Related Questions