35

How can I trigger an update when altering part of an object found by index in an array?

The docs show how to alter the value of an array:

Vue.set(example1.items, indexOfItem, newValue)

or

example1.items.splice(indexOfItem, 1, newValue)

But how to alter the value of a property on an object in an array without changing the rest of the object?

The following works to update the property, but Vue doesn't react to the change until something else triggers an update.

example1.items[indexOfItem].some_object_property = false

4 Answers 4

18

You could update the sub-property in the array element with this.$set(). For example, to increment an x subproperty in the first two array elements (creating the sub-property if it doesn't exist):

methods: {
  update() {
    this.$set(this.arr[0].foo, 'x', (this.arr[0].foo.x || 0) + 100)
    this.$set(this.arr[1].foo, 'x', (this.arr[1].foo.x || 0) + 100)
  }
}

new Vue({
  el: '#app',
  data() {
    return {
      arr: [
        {
          foo: {
            x: 100,
            y: 200
          }
        },
        {
          foo: {
            /* x does not exist here initially */
            y: 400
          }
        }
      ]
    };
  },

  methods: {
    update() {
      this.$set(this.arr[0].foo, 'x', (this.arr[0].foo.x || 0) + 100)
      this.$set(this.arr[1].foo, 'x', (this.arr[1].foo.x || 0) + 100)
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>

<div id="app">
  <button @click="update">Update</button>
  <p>arr[0]: {{ arr[0] }}</p>
  <p>arr[1]: {{ arr[1] }}</p>
</div>

codepen

Sign up to request clarification or add additional context in comments.

Comments

8

As long as you call set() once to set the object (with the property you are going to update) in the array, Vue will react to changes in the object's properties. Here's an example that has one array of objects initialized in our app's data, and another array of objects manually set (with Vue.set()) when mounted. Clicking the button updates a property on one object in each of those arrays, and Vue reacts. Note that the set() call that happens in mount() could really happen anytime.

https://codepen.io/jordan-kalosal/pen/VrwjoR

new Vue({
  el: "#app",
  data: {
    arr: [
      {
        property: 'OBJ1 Prop'
      },
      {
        property: 'OBJ2 Prop'
      }
    ],
    setLater: false
  },
  mounted() {
    this.$set(this, 'setLater', [
      {
        property: 'setLater OBJ1 Prop'
      },
      {
        property: 'setLater OBJ2 Prop'
      }
    ])
  },
  methods: {
    _updateObjProps() {
      this.arr[0].property = (new Date()).toString();
      this.setLater[0].property = (new Date()).toString();
    }
  }
})

2 Comments

What is 'OBJ1 Prop', is this really a string? It's not very clear
@Bersan Yes in this case 'OBJ1 Prop' is really a string. I was just creating an example of an array with some data in it. property and OBJ1 Prop could both be anything you want, they're just example properties and values that comprise objects in this example array (arr).
8

Here is another demo example that I think give a good illustration of the reactivity of objects inside an array. Try it live here: https://codepen.io/antoniandre/pen/ZdjwKG

JS

new Vue({
  el: "#app",
  data: {
    array: []
  },

  methods: {
    addTimeProp() {
      this.array.forEach(item => {
        this.$set(item, 'time', null)
      })
    },
    updateTimeProp() {
      this.array.forEach(item => {
        item.time = (new Date()).toString()
      })
    }
  },

  created () {
    this.array.push({ name: 'today' }, { name: 'tomorrow' })
  }
})

HTML: PUG

#app
  h1 Reactivity of objects inside an array
  h2 Content of the array
  pre {{ array }}
  button(@click="array.push({ name: 'another day' })") Add another object
  button(@click="addTimeProp") Add `time` property
  button(@click="updateTimeProp") Update `time` property

Comments

4

You can also do it like this if you don't create any new property:

this.myArray.find( el => el.id === '123').someValue = 'someValue'

Objects inside an array are completely reactive.

Comments

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.