Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

vue.js

v-for

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!

like image 540
KasparTr Avatar asked Nov 30 '18 11:11

KasparTr


People also ask

Is V model reactive?

Vue3 v-model objects are not reactive.

How do you use reactive in Vue 3?

To make it reactive we will use “reactive()” function; ##004 we can include also “computed properties” in the reactive object. You can access computed properties accessing to the object properties (game. total in this case);

What does $Set do in Vue?

Vue. set is a tool that allows us to add a new property to an already reactive object, and makes sure that this new property is ALSO reactive.


3 Answers

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.

like image 105
Fleeck Avatar answered Jan 16 '23 21:01

Fleeck


Try that:

downloadSomething(newId).then(res => {
    this.$set(this.objects, 'newId', res[0])
})
like image 39
Roland Avatar answered Jan 16 '23 19:01

Roland


you need Vue.set() when you want to define a new property to an existing object (not directly to the data), and this function will assign the new property to the built-in watcher, and it will become reactive as well.

its all being explained in the docs: https://v2.vuejs.org/v2/guide/reactivity.html

in your case, it seems to be all you need to make it work. in my example:https://jsfiddle.net/efrat19/eywraw8t/484131/ an async function fetches the data and define a new property to contain te response.

new Vue({
  el: "#app",
  data: {
    objects:{
    property1:12
    }
  },
  methods: {
    fetchDataAndAddProperty(response){
        fetch('https://free.currencyconverterapi.com/api/v6/countries').then(res =>
      res.json()).then(data => Vue.set(this.objects,'property2',data))
    }
  }
})

and the template:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

<div id="app">
<div lg="12" v-for="(val,key,index) in objects" :key="index">
    {{key}}:{{val}}
</div>
<button @click="fetchDataAndAddProperty()">fetch</button>
</div>

as you can see in the fiddle, the new property becomes reactive and being displayed as well.

like image 36
Efrat Levitan Avatar answered Jan 16 '23 19:01

Efrat Levitan