web-dev-qa-db-fra.com

Propriétés de l'objet de liaison Vue.js

Pourquoi je ne peux pas lier les propriétés de l'objet dans Vue? L'objet addr n'est pas réactif immédiatement, mais test est réactif, comment se fait-il? Dans ce cas, comment dois-je le lier?

HTML

<div id="app">

   <input type="text" id="contactNum" v-model="addr.contactNum" name="contactNum">

   <input type="text" id="test" v-model="test" name="test">
   <br/>
   {{addr}}<br/>
   {{addr.contactNum}}<br/>
   {{test}}
</div>

Javascript

var vm = new Vue({
    el: '#app',
    data: {
      addr: {},
      test: ""
    }
});

Jsfiddle

7
GMsoF

Lors de l'initialisation Vue configure les getters et setters pour chaque propriété connue. Puisque contactNum n'est pas initialement configuré, Vue ne sait pas à propos de cette propriété et ne peut pas la mettre à jour correctement. Cela peut être facilement corrigé en ajoutant contactNum à votre addr objet.

var vm = new Vue({
  el: '#app',
  data: {
    addr: {
      contactNum: "" // <-- this one
    },
    test: ""
  }
});

Ce qui précède est appelé réactivité dans Vue. Étant donné que Vue ne prend pas en charge l'ajout dynamique de propriétés à son système de réactivité, nous pouvons avoir besoin d'une sorte de solution de contournement. Une solution possible - solution est fournie par l'API. En cas de propriétés ajoutées dynamiquement, nous pouvons utiliser Vue.set(vm.someObject, 'b', 2).

Pour ce faire, le balisage devrait obtenir une mise à jour. Au lieu d'utiliser v-model, Il serait préférable d'utiliser un écouteur d'événement comme @input. Dans ce cas, notre balisage pourrait ressembler à ceci.

<input type="text" id="contactNum" @input="update(addr, 'contactNum', $event)" name="contactNum">

Donc, fondamentalement, la fonction sera déclenchée chaque fois que la valeur des éléments d'entrée change. Évidemment, cela nécessitera également quelques ajustements sur la partie JS.

var vm = new Vue({
  el: '#app',
  data: {
    addr: {},
    test: ""
  },
  methods: {
    update: function(obj, prop, event) {
      Vue.set(obj, prop, event.target.value);
    }
  }
});

Puisque Vue déclenche Vue.set() sur n'importe quel élément réactif, nous l'appelons simplement par nous-mêmes car Vue ne reconnaît pas une propriété ajoutée dynamiquement) comme réactif. Bien sûr, ce n'est qu'une solution possible et il peut y avoir beaucoup d'autres solutions de contournement. Un exemple pleinement fonctionnel peut être vu ici .

12
Aer0

Selon mes commentaires, il y a plusieurs choses que vous souhaitez considérer:

  • La raison pour laquelle votre code ne fonctionne pas est due à l'incapacité inhérente de JS à surveiller les changements dans les propriétés des objets . Cela signifie que même si addr est réactif, toutes les propriétés ajoutées à addr qui ne sont pas effectuées lors de sa déclaration le rendront non réactif. Reportez-vous aux documents VueJS pour plus de détails: https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
  • Si vous allez avoir un nombre arbitraire de champs de saisie, il vaut probablement mieux composer un composant de saisie personnalisé , et utilisez simplement v-for pour injecter de manière itérative des champs d'entrée en fonction du nombre de champs d'entrée que vous avez.

Revenons maintenant au deuxième point, si vous savez quels champs addr aura, vous pouvez simplement le déclarer dans votre application. Nous créons une nouvelle méthode updateFormData, qui est appelée par le composant:

data: {
  addrFields: ['contactNum', ...],
  addr: {},
  test: ""
},
methods: {
  updateFormData: function(id, value) {
    this.$set(this.addr, id, value);
  }
}

Nous pouvons toujours stocker vos données de formulaire dans l'objet addr, qui sera mis à jour par la méthode updateFormData en fonction de la charge utile reçue à l'aide de .$set() . Maintenant, nous pouvons ensuite créer un composant Vue personnalisé pour votre élément d'entrée.

Dans l'exemple ci-dessous, le composant parcourt tous vos addrFields et transmet le addrField comme accessoire en utilisant :id="addrField". Nous voulons également nous assurer que nous capturons l'événement updated nommé personnalisé, émis à partir du composant.

<my-input
     v-for="(addrField, i) in addrFields"
     :key="i"
     :id="addrField"
     v-on:inputUpdated="updateFormData"></my-input>

Le modèle peut ressembler à ce qui suit. Il utilise simplement le prop id pour ses attributs id, name et placeholder (ce dernier pour une identification facile dans la démo). Nous lions les événements @change Et @input, Le forçant à déclencher le rappel updated:

<script type="text/template" id="my-input">
    <input
    type="text"
    :id="id"
    :name="id"
    :placeholder="id"
    @input="updated"
    @change="updated">
</script>

Dans la logique du composant, vous lui faites savoir qu'il recevra id comme accessoire et qu'il devrait émettre un événement inputUpdated en utilisant $.emit() =. Nous attachons l'ID et la valeur en tant que charges utiles, afin de pouvoir informer le parent de ce qui a été mis à jour:

var myInput = Vue.component('my-input', {
    template: '#my-input',
  props: {
    id: {
        type: String
    }
  },
  methods: {
    updated: function() {
        this.$emit('inputUpdated', this.id, this.$el.value);
    }
  }
});

Avec le code ci-dessus, nous avons un exemple de travail. Dans ce cas, j'ai créé un tableau arbitraire de champs de saisie: contactNum, a, b et c:

var myInput = Vue.component('my-input', {
        template: '#my-input',
  props: {
        id: {
        type: String
    }
  },
  methods: {
        updated: function() {
        this.$emit('updated', this.id, this.$el.value);
    }
  }
});

var vm = new Vue({
    el: '#app',
    data: {
      addrFields: ['contactNum', 'a', 'b', 'c'],
      addr: {},
      test: ""
    },
    methods: {
        updateFormData: function(id, value) {
        this.$set(this.addr, id, value);
      }
    }
});
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
   
   <my-input
     v-for="(addrField, i) in addrFields"
     :key="i"
     :id="addrField"
     v-on:updated="updateFormData"></my-input>
   
   <input type="text" id="test" v-model="test" name="test" placeholder="test">
   <br/>
   <strong>addr:</strong> {{addr}}<br/>
   <strong>addr.contactNum:</strong> {{addr.contactNum}}<br />
   <strong>test:</strong> {{test}}
</div>

<script type="text/template" id="my-input">
        <input
        type="text"
    :id="id"
    :name="id"
    :placeholder="id"
    @input="updated"
    @change="updated">
</script>
4
Terry

Modifiez votre Vue data avec ceci car ses méthodes getter et setter ne sont pas configurées. Consultez également Rendu réactif déclaratif sur Vue docs ici :

data: {
    addr: {
      contactNum: "" // <-- this one
    },
    test: ""
  }
0
hamzox