Reputation: 266
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
Upvotes: 14
Views: 14264
Reputation: 354
After much searching, this link helped me: How can I clone data from Vuex state to local data? Basically use the beforeMount()
method, then edit as you please :)
Upvotes: 0
Reputation: 381
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.
Upvotes: 1
Reputation: 266
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,
Upvotes: 3