Grimson
Grimson

Reputation: 572

VueJS reactivity issue for object inside array

I've declared my data object as queuedItemList: [] which is supposed to contain an array of items provided by a background service. After the HTTP request, I populate the list using a for loop like

for(var i = 0; i < getList.length; i++) {
    var newObject = Object.assign({}, getList[i]);
    this.queuedItemList.splice(i, 1, newObject);
}

which is used to populate the following template

<Item v-for="(item, index) in queuedItemList" :key="index" :componentData="item" :index="index" @remove="removeItem">
</Item>

I am supposed to do a periodic HTTP GET to get the new list of items, which may also contain current items with maybe different state. Inside the component, I am using a v-if to select between two different icons.

<v-icon name="play" class="controlIcons" v-if ="playControl" />
<v-icon name="pause" class="controlIcons" v-if ="!playControl" />

Now, after some HTTP requests, I see the value of playControl change in Vue Devtools which confirms that the actual value is reflected in the component. However, I can't see the icons change due to the change in the value of playControl. Furthermore, everything works as expected if I refresh the screen.

My guess is that I'm messing up the reactivity somewhere. Thanks!

Upvotes: 2

Views: 4066

Answers (4)

Julliano Osorio
Julliano Osorio

Reputation: 305

i don't know the structure of "playcontrol"

<v-icon name="play" class="controlIcons" v-if ="playControl" />

I passed by something similar in past, when you update "playControl" value, you do just "playControl = newValue"? If you do, this can screw up the reactivity, try use Vue $set directive, like:

Vue.set(this.playControl, <value>);

https://v2.vuejs.org/v2/guide/migration.html#vm-set-changed

Upvotes: 0

alx.lzt
alx.lzt

Reputation: 486

You're looking for https://v2.vuejs.org/v2/guide/reactivity.html

for(var i = 0; i < getList.length; i++) {
    var newObject = Object.assign({}, getList[i]);
    this.$set(this.queuedItemList, i, newObject);
}

Another method might be to update the parent's item list :key - thus, rerendering it - everytime you add an item:

</div :key="computedKey">    
    <Item v-for="(item, index) in queuedItemList" :key="index" :componentData="item" :index="index" @remove="removeItem"></Item>
</div>

With

computed: {
    computedKey () {
        return this.queuedItemList.length
    }
}

Upvotes: 7

yashwanth kumar
yashwanth kumar

Reputation: 65

You can use several properties for reactivity check, $set to change the property in an object, $nextTick to assign the value.

If the both don't work you may try $forceUpdate()

Upvotes: 0

Grimson
Grimson

Reputation: 572

Turns out what I needed was a combination of setters and watchers. I used @alx.lzt's setters and a watcher on the component level and that solved everything

Upvotes: 0

Related Questions