I'm using Vue with Vuex for central storage management. I have a list of object in the store that are frequently updated by a setTimeout function. I want to let the user select and edit it with a two-way data binding form. My problem is that whenever any data in the store gets updated, also the selected object that is being modified by the user gets re-rendered. In this way the user loses the changes.
The solution would be to clone the object from the Vuex store to a local data object and bind it to the form to prevent updates while editing it. I tried every possible way to clone the observable object that Vuex returns without success. In particular I tried the following methods:
JSON.parse(JSON.stringify(obj))
and
Object.assign({}, vueObj)
and also other deep cloning methods from external libraries like _ and jQuery.
this is the object that I get from the Vuex store:
If i stringify it, parse it and assign to a local vue data object it gets updated whenever the Vuex central storage is updated.
Here is my code (component only, not Vuex store):
<template>
<div class="">
<div v-if="localSelectedDataSource.id">
{{localSelectedDataSource.name}}
</div>
<div v-if="localSelectedDataSource.id">
<div><sui-input placeholder="Url" :value="localSelectedDataSource.url"/></div>
<div>{{localSelectedDataSource.method}}</div>
<div>{{localSelectedDataSource.pollingInterval}}</div>
</div>
<div class="datasource-list">
<div
v-bind:class="{ highlightdatasource: dataSource.view.highlighted }"
v-for="dataSource in dataSources"
v-on:mouseover="highlightDataSource(dataSource.id)"
v-on:mouseout="highlightDataSource(-1)"
v-on:click="editSelectedDataSourceLocal(dataSource.id)"
>
{{dataSource.name}} - {{dataSource.url}}
</div>
</div>
</div>
</template>
<script>
import {mapGetters} from 'vuex';
import {mapActions} from 'vuex';
export default {
name: 'DataSourceList',
data(){
return{
localSelectedDataSource: {}
}
},
computed: {
...mapGetters([
'dataSources',
'selectedDataSource'
])
},
methods: {
...mapActions([
'highlightDataSource',
'editSelectedDataSource'
]),
editSelectedDataSourceLocal: function(id){
this.editSelectedDataSource(id)
var t = JSON.parse(JSON.stringify(this.selectedDataSource))
if(this.localSelectedDataSource.id != this.selectedDataSource.id){
this.localSelectedDataSource = t
}
}
}
}
</script>
Thank you
vuex-local achieves simple and trackable local state management. We can define a local Vuex module in each component and it will be registered on a Vuex store. This let us use features of dev tools such as time-travel debugging for local state. In addition we can use a local module on a component in natural way.
But let's look at the doc, it states "The only way to actually change state in a Vuex store is by committing a mutation". Oh, so maybe you misunderstand the recommendation to never mutate state outside of a mutation to mean that vuex enforces this by creating immutable objects? That's not the case.
If you are going to put data from vuex directly into a component do not use v-model as that will write changes to the vuex store data automatically. Use v-bind:value and v-on:input instead to control what happens when there is an input event (like dispatching actions to update the store instead of modifying directly) .
Or the Vuex observables can be mutated but it does not affect the state in any way. But that would make it a bit too ambiguous in my mind. Okey I figured out why the observable wasn't working, I didn't declare the variable in the data () -block.
After many hours of debugging, my friend and I found my error:
I used the v-bind shorthand :
<div><sui-input placeholder="Url" :value="localSelectedDataSource.url"/></div>
rather than two-way binding v-model
<div><sui-input placeholder="Url" v-model="localSelectedDataSource.url"/></div>
so every time that the central vuex store was updated, my component data binding re-rendered, including the local copy bound to the form.
Thanks to everyone,
If you want to use v-model you should use a computed property. You'd make a computed property that returns the value that is in the store than use that computed property in the v-model. By the way v-model is syntactic sugar for:
:value="someData" @input="someData=$event.target.value"
It probably works with :value because the @input isn't there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With