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: ""
}
});
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 .
Selon mes commentaires, il y a plusieurs choses que vous souhaitez considérer:
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-Caveatsv-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>
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: ""
}