RichC
RichC

Reputation: 7879

How to loop through an array and add a property to all objects in vue.js

In Vue.js, in order to add a property/array item to something already in the virtual DOM, you have to use the $set function.

Here are the wrong ways:
Object: this.myObject.newProperty = "value";
Array: this.myArray[3] = object;

Here's the right way:
Object: this.$set(this.myObject, "newProperty", "value");
Array: this.$set(this.myArray, 3, object);

My question is how do you $set a property of all objects in an array?

Here's the wrong way:

for (var i = 0; i < this.myArray.length; i++) {
    this.myArray[i].newProperty = "value";
}

So, what's the method for me to use $set to do this?

Upvotes: 2

Views: 4631

Answers (4)

amirify
amirify

Reputation: 805

You simply just wanna add a new property to objects in an array. Not set a new value to the array by their index. You can do the following:

new Vue({
    el: '#demo',
    data: {
        myArray: [
            {id: 1},
            {id: 2},
            {id: 3},
            {id: 4},
            {id: 5}
        ]
    },
    methods: {
        addProperties() {
            for (var i = 0; i < this.myArray.length; i++) {
                this.$set(this.myArray[i], 'newProperty', 5 - i)
            }
        }
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
    <div v-for="item in myArray" :key="item.id">
        <span>{{item.id}}: </span>
        <span v-if="item.newProperty">{{item.newProperty}}</span>
    </div>
    <button @click="addProperties">Add Properties</button>
</div>

Upvotes: 2

muka.gergely
muka.gergely

Reputation: 8329

A bit tweaked code of yours works:

new Vue({
  el: "#app",
  data: {
    todos: [{
        text: "Learn JavaScript",
        done: false
      },
      {
        text: "Learn Vue",
        done: false
      },
      {
        text: "Play around in JSFiddle",
        done: true
      },
      {
        text: "Build something awesome",
        done: true
      }
    ]
  },
  methods: {
    toggle: function(todo) {
      todo.done = !todo.done
    },
    changeProperty1() {
      const val = 'A'
      // this is your code a bit modified
      // defining length (and using it in the comparison) is a
      // bit of optimization, not required
      for (var i = 0, length = this.todos.length; i < length; i++) {
        this.$set(this.todos[i], 'property1', val);
      }
    },
    changeProperty1Again() {
      for (todo of this.todos) {
        if (todo.property1) {
          todo.property1 = 'B'
        }
      }
    }
  },
  created() {

  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <h2>Todos:</h2>
  <ol>
    <li v-for="todo in todos">
      <label>
        <input type="checkbox"
          v-on:change="toggle(todo)"
          v-bind:checked="todo.done">

        <del v-if="todo.done">
          {{ todo.text }}
        </del>
        <span v-else>
          {{ todo.text }}
        </span>
        <span>
          {{ todo.property1 }}
        </span>
      </label>
    </li>
  </ol>
  <button @click="changeProperty1">Click this first</button>
  <button @click="changeProperty1Again">Click this second</button>
</div>

Sorry for the lengthy snippet, I just copied it over from JSFiddle :)

Upvotes: 2

HalfWebDev
HalfWebDev

Reputation: 7668

You keep doing this.$set(this.myArray, 3, object); in a loop using the index. Something like this after modifying your object.

var newObject = Object.assign({}, this.myArray[i], {newProperty: 'value'} ); // Immutable object created
this.$set(this.myArray, i, newObject);

This will be inefficient as it will call $set for each iteration. so you can do a map on your array and return a new Object from inside.

const newArray = myArray.map(object => {
   return Object.assign({}, object, {newProperty: 'value'} );
   //or by ES6 spread operator
   return {...object, newProperty: 'value'};
});

Then set your array for Vuejs to re-render.

Hope, this will give the idea. Although context(this) may vary depending on how you're implementing!

Upvotes: 2

A Macdonald
A Macdonald

Reputation: 824

Not really a vue thing - just plain JS:

arr.map(obj => { return {...obj, newProperty: "sameValueAsOthers"}});

Upvotes: 0

Related Questions