web-dev-qa-db-fra.com

Objet clone Vuex pour l'édition locale

J'utilise Vue avec Vuex pour la gestion du stockage central. J'ai dans le magasin une liste d'objets fréquemment mis à jour par une fonction setTimeout. Je veux laisser l'utilisateur sélectionner et éditer avec un formulaire de liaison de données bidirectionnel. Mon problème est que chaque fois que des données du magasin sont mises à jour, l'objet sélectionné en cours de modification par l'utilisateur est également restitué. De cette façon, l'utilisateur perd les modifications.

La solution serait de cloner l'objet du magasin Vuex sur un objet de données local et de le lier au formulaire pour empêcher les mises à jour lors de sa modification. J'ai essayé tous les moyens possibles pour cloner l'objet observable renvoyé par Vuex sans succès. J'ai notamment essayé les méthodes suivantes:

JSON.parse(JSON.stringify(obj))

et 

Object.assign({}, vueObj)

ainsi que d'autres méthodes de clonage en profondeur issues de bibliothèques externes telles que _ et jQuery.

voici l'objet que je reçois du magasin Vuex:

 enter image description here

Si je le stringifie, analysez-le et assignez-le à un objet de données vue local, il sera mis à jour à chaque mise à jour du stockage central Vuex.

Voici mon code (composant uniquement, pas le magasin Vuex):

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

Je vous remercie

5
Alessandro

Après plusieurs heures de débogage, mon ami et moi avons trouvé mon erreur:

J'ai utilisé le raccourci v-bind:

<div><sui-input placeholder="Url" :value="localSelectedDataSource.url"/></div>

plutôt que la liaison à double sens v-model

<div><sui-input placeholder="Url" v-model="localSelectedDataSource.url"/></div>

ainsi, chaque fois que le magasin central vuex était mis à jour, ma liaison de données de composant était restituée, y compris la copie locale liée au formulaire.

Merci à tout le monde,

3
Alessandro

Si vous voulez utiliser v-model, vous devez utiliser une propriété calculée. Vous feriez une propriété calculée qui renvoie la valeur qui se trouve dans le magasin plutôt que d'utiliser cette propriété calculée dans le modèle-v. En passant, v-model est un sucre syntaxique pour:

:value="someData" @input="someData=$event.target.value"
Cela fonctionne probablement avec: value car le @input n’est pas là.

1
derFBeste

Après de nombreuses recherches, ce lien m’a aidé: Comment cloner des données de l’état Vuex en données locales? Fondamentalement, utilisez la méthode beforeMount(), puis éditez à votre guise :)

0
Misrab