This is my first post here, if I'm not mistaken, so let me say thank you for an amazing framework which inspires us all!
I maintain a package called contextable.js. It uses schema-based objects to describe application's data model and its primary focus is to simplify server-side and client-side data validation. I've been using it in Express.js and GraphQL resolvers for now, but recently I also started using it in Vue.js through vue-contextable plugin.
I'm not sure if this is a bug report or a feature request but I kindly ask for directions on how to handle v-model
reactivity in a complex object where arrays of class instances are used. I suspect that Vue.js can't track changes on arrays of class instance objects though I'm not sure what would be the difference in this case compare to an Object
. I've created an example here so you can try it yourself.
Vue.js version: 2.1.0
Reproduction Link: https://github.com/xpepermint/vue-contextable-example
Steps to reproduce: Run the example and play with the provided form.
What is Expected?: The user
model should be updated when input changes.
What is actually happening?: The model is not updated.
I'm not entirely sure about the cause, but most likely it's because Vue's observer only converts an object's own properties into reactive ones (i.e. it ignores prototype properties).
Technically, if the "data" properties of your model objects are "own properties", then it should be able to work: https://jsfiddle.net/1a51gez4/
Thanks @yyx990803. I went through the documentation again and I found this paragraph:
Sometimes you may want to assign a number of properties to an existing object, for example using Object.assign() or _.extend(). However, new properties added to the object will not trigger changes. In such cases, create a fresh object with properties from both the original object and the mixin object.
This is exactly what the problem is. I'll close this issue since I see how to solve it now. Thanks!
I'll close this issue since I see how to solve it now.
@xpepermint, can you share the way you solved the problem?
Thanks!
@maximelebreton I remember that I managed to make it work somehow, I think I was setting attributes manually within observer (on change), but at the end I decided to change the component design to the non-nested way. My projects now not don't have nested components (e.g. Table component has head,body,row but it's a single .vue
file).
@yyx990803 Computed properties should be have same behaviour. Why is not working?
@mikeevstropov computed doesn't convert the returned value. It needs to be reactive before being returned.
@yyx990803 Thank you for reply!
Thanks @yyx990803. I went through the documentation again and I found this paragraph:
Sometimes you may want to assign a number of properties to an existing object, for example using Object.assign() or _.extend(). However, new properties added to the object will not trigger changes. In such cases, create a fresh object with properties from both the original object and the mixin object.
This is exactly what the problem is. I'll close this issue since I see how to solve it now. Thanks!
This solved my issue. I will show both to help show what he's talking about:
This is problematic:
this.modifiedAccount.billing_city = newLocation.city;
this.modifiedAccount.billing_region = newLocation.region;
That is problematic because billing_city
and billing_region
were not keys on modifiedAccount
, so they were basically not being watched, is how I interpret that.
This is a solution to that problem:
this.modifiedAccount = {
...this.modifiedAccount,
billing_city: newLocation.city,
billing_region: newLocation.region,
};
This overwrites modifiedAccount
with a copy of itself plus the new keys spread in, which will be familiar to many people, as it is a common immutable approach.
Without testing, I am pretty sure this.modifiedAccount.billing_city = newLocation.city;
would trigger a re-render after you did the above solution because Vue would then be watching those keys.
EDIT: I just tested and the component did re-render after I did the above solution and then did:
this.modifiedAccount.billing_city = 'poop';
Just for reference at the forum
https://forum.vuejs.org/t/object-assign-not-triggering-reactivity/3289
Although @agm1984's solution works I simply added a {} as the first argument of Object.assign which creates a new complete object and which did the trick in terms of reactivity.
state.props = Object.assign({}, state.props, mixinprops)
Most helpful comment
Thanks @yyx990803. I went through the documentation again and I found this paragraph:
This is exactly what the problem is. I'll close this issue since I see how to solve it now. Thanks!