Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vuex clone object for local editing

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:

enter image description here

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

like image 663
Alessandro Avatar asked Jan 17 '18 02:01

Alessandro


People also ask

What is Vuex-local and how to use it?

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.

How to change state in a Vuex store?

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.

How do I put data from Vuex directly into a component?

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) .

Can Vuex observables be mutated?

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.


2 Answers

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,

like image 157
Alessandro Avatar answered Sep 20 '22 20:09

Alessandro


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.

like image 28
derFBeste Avatar answered Sep 22 '22 20:09

derFBeste