Vue: How to perform reactive object change detection in v-for?

KasparTr picture KasparTr · Nov 30, 2018 · Viewed 7.9k times · Source

I read this documentation but cannot use the proposed solution.

I have a v-for loop over objects. These objects are changed dynamically over time and I need that change to show reactively in the v-for loop.

<b-row lg="12" v-for="data in objects" :key="data.id">
    <div v-if="data.loading">
      loading...
      {{data.loading}}
    </div>
    <div v-else>
      loaded, done
      {{data.loading}}
    </div>
</b-row>

In my methods, I have a for loop that downloads data for each object and changes the object value like this:

for(var i = 0; i<response.ids.length; i++){
    var newId = response.ids[i].id
    this.objects.newId = {"loading":true, "id": newId}

    downloadSomething(newId).then(res => {
        this.objects.newId = res[0]         //<-- this change needs to be shown reactively.
    })
}

According to Vue documentation, Object changes are not reactive:

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` is now reactive

vm.b = 2
// `vm.b` is NOT reactive

Vue propses some workaround like this:

Vue.set(vm.userProfile, 'age', 27)

UPDATE

But for my case, this just creates a new parameter in the object with the same ID and creates a duplicate key warning and other problems.

I also tried Vue.delete just before Vue.set but it is not actually deleting.

Is there a way to not replace the key/value pair but add more/change parameters to the first child of the root with the ID of newID

Thanks!

Answer

Fleeck picture Fleeck · Nov 30, 2018

Solution: Replace this.objects.newId = res[0] with this.$set(this.objects, 'newId', res[0]) and it should work.

Explanation: this.$set is just an alias to Vue.set, available within any Vue instance. Bear in mind that vm (stands for view model) in the example is the same as this and equals to Vue component instance. Also due to ES5 JS restrictions, you have to set objects' properties explicitly via Vue.set/this.$set to manually trigger re-render. This problem will be resolved when Vue 3.0 is released.

Hope this helps, if you need any clarifications - feel free to ask.