aleng
aleng

Reputation: 428

How to $set a property to multiple objects in an array but have retain individual reactivity in vue js

In my case, I have data array with multiple objects

data() {
 return {
   selected: 0,
   presetData: [true, true, true],
   data: [
     {
       name: "name 1"
     },
     {
       name: "name 2"
     }
   ]
 };

},

then I want to push inside each object in data like below

setNewData() {
  this.data.forEach((o, i) => {
    this.$set(this.data[i], "time", this.presetData);
  });
},

now my with presetData pushed into data will look like this

data: [
    {
      name: "name 1",
      time: [true, true, true]
    },
    {
      name: "name 2",
      time: [true, true, true]
    }
  ]

and I want to change individual time property of each object, which I use something like below

$set(item.time,selected,true)

My Issue

my issue is, this going to change both objects time property. How do I first push/set correctly presetData to data, below is my entire code , I'm sorry I'm very new to programming, here is the link to jsfiddle

    new Vue({
  el: "#app",
  data() {
    return {
      selected: 0,
      presetData: [true, true, true],
      data: [
        {
          name: "name 1",
        },
        {
          name: "name 2",
        }
      ]
    };
  },
  methods: {
    setNewData() {
      this.data.forEach((o, i) => {
        this.$set(this.data[i], "time", this.presetData);
      });
    },
  }
})

  <div id="app">
<button @click="setNewData">Set Data</button>
<br>
<br>
<select v-model="selected">
  <option>0</option>
  <option>1</option>
  <option>2</option>
</select>
<div v-for="item in data" :key="item.id">
  <p>{{item.name}}</p>
  <p>{{item.time}}</p>
  <button @click="$set(item.time,selected,true)">Change True</button>
  <button @click="$set(item.time,selected,false)">Change False</button>
</div>

Upvotes: 2

Views: 1124

Answers (1)

Phil
Phil

Reputation: 165065

This is an object reference issue. Each of your time properties references the same array (presetData). You can break out of this problem by making shallow copies via spread syntax.

You can also avoid Vue.set() when assigning new data using the same technique

setNewData() {
  this.data = this.data.map(d => ({
    ...d, // create a shallow copy of each data item
    time: [...this.presetData] // add "time" as a shallow copy of presetData
  }))
},

To change individual array elements within the time property, you need to continue using Vue.set(), ie

this.$set(item.time, selected, true)

Upvotes: 2

Related Questions