Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$set for modifying objects in array for reactivity #4443

Closed
donnyjeremiah opened this issue Dec 11, 2016 · 10 comments
Closed

$set for modifying objects in array for reactivity #4443

donnyjeremiah opened this issue Dec 11, 2016 · 10 comments

Comments

@donnyjeremiah
Copy link

Vue.js version

2.1.0

Problem:

I can't update an object in my array of objects editedPlayers[] when I use this.$set(). When I try to do this.editedPlayers.$set(id, this.editedPlayers[id].stats[type] + 1). I know this is wrong.

editedPlayers[{stats:{goals: 12, assists:3, played: 10}}, {stats:{goals: 23, assists:7, played: 30}}]

I want to update the stats.goals in editedPlayers[someId]. Since $set or splice() can be used to substitute the current index value with another, I want just to modify it (ie: stats.goals). What do I do?

@yyx990803
Copy link
Member

Please make sure to read the Issue Reporting Guidelines before opening new issues. The issue list only accepts bug reports and feature requests. Questions should be posted to the Gitter chat room, forum or StackOverflow. Thanks.


You just do editedPlayers[id].stats[type]++. If the property is already observed there's no need to use $set at all.

Also, in 2.0 Arrays are no longer augmented with $set, and this.$set on component instances are also different from the 1.x version: https://vuejs.org/v2/api/#vm-set

@donnyjeremiah
Copy link
Author

donnyjeremiah commented Dec 14, 2016

When I do this.editedPlayers[id].stats[type]++, Vue doesn't detect the change because I am "directly setting an item with the index". See this, https://vuejs.org/v2/guide/list.html#Caveats. Now, this.$set only allows me to 'substitute' a value in the array given the key, with another value. I want to 'modify' editedPlayers[id].stats[type] and not entirely replace editedPlayers[id].

Also thank you for pointing out that Arrays are no longer augmented with $set, 2.0 onward.

@yyx990803
Copy link
Member

No, the actual mutation happens on the object inside the array, not the array itself, so it is not subject to the index detection caveat.

@donnyjeremiah
Copy link
Author

donnyjeremiah commented Dec 14, 2016

I've made this repo to show you the problem. Please take a look at it.

https://jsfiddle.net/donnyjeremiah/tfvouu61/1/

You can see here that once editedPlayers['someID'] is loaded for the first time in the interpolation with the {{ }}, it isn't picking up the updated state which is being changed in the editPlayerStat() method later. However you do see in the console that editedPlayers['someID'] is actually being updated. This is my problem. I need it to be updated in within the curly brackets, {{ }}.

Note, that I have a button refresh which when clicked causes the {{ }} to re-render and hence I get the current value. So basically, editedPlayers['someID'] in {{ }} is loading fine but isn't being updated.

P.S: I've tried using this.$set() to rewrite the whole value, but since this.$set() takes the 'index' of the indexed array as second argument, I run into another problem and that is because my 'index' is a string and basically there is no such thing as associative arrays in javascript. And hence, I get thrown the error, array length too big....

@yyx990803
Copy link
Member

You seem to have a misunderstanding of how JavaScript array works... the way you are using it is like an Object hash, not an Array. Mutations to Arrays in JavaScript happen through methods like push() and pop().

Doing this is adding a new property to the Array as an Object, not pushing a new element to the Array:

arr['someId'] = { ... }

But this is not what Arrays are for. If you want to store things with string keys you should use an Object.

And since you are adding a new property, you should use Vue.set().

@donnyjeremiah
Copy link
Author

donnyjeremiah commented Dec 14, 2016

Yeah, I understood that an array with strings for indexes is basically an object with a property, when I was creating this repo. I didn't know that before. But there is one thing. Despite, the way or purpose I've used the array, why isn't Vue updating it? It should, shouldn't it? So since arr['someId'] is just arr.someId and can be accessed by arr['someId'] AND arr.someId, why isn't it updating?

P.S: Also if I was using objects, I wouldn't be adding a property, I would be 'modifying it'. Modifying editedPlayers['someID'].stats.goals.

@simplesmiler
Copy link
Member

simplesmiler commented Dec 14, 2016

Oh boy.
Here is your fixed fiddle: https://jsfiddle.net/tfvouu61/2/
Please note Vue.set and read Change Detection Caveats once again.

@donnyjeremiah
Copy link
Author

@simplesmiler Thank you :) So just to clarify, because I'm very restless when I don't know what it was that I did wrong, was it because that I was using Vue.set() to update the value instead of using it to set the object to begin with? And did I hit the change detection caveat?

@simplesmiler
Copy link
Member

Yes. Vue was unable to detect the addition of a new property someID to the object this.editedPlayers due to the limitations of JavaScript.

@donnyjeremiah
Copy link
Author

Evan Almighty! So I wasn't insane after all! It's just that I wasn't sure what problem I was running into. Thank you @simplesmiler and @yyx990803! You guys have good day :)

@vuejs vuejs deleted a comment from dexygen Oct 4, 2017
@vuejs vuejs locked and limited conversation to collaborators Oct 4, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants