2017-07-12 2 views
2

Ich wollte eine wechselseitige Datenbindung für meine Formulareingabe in Vue.js 2.3 erstellen. Ich kann die Anweisung v-model jedoch nicht verwenden, da die Daten nur beim Klicken auf die Schaltfläche zum Senden aktualisiert werden sollen. In der Zwischenzeit kann der Eingabewert von einer anderen Vue-Methode aktualisiert werden, daher sollte er an die Dateneigenschaft text gebunden sein. Ich nahm etwas wie dieses jsFiddle:Wie verzögere ich die Formulareingabebindung, bis der Benutzer auf die Senden-Schaltfläche klickt?

<div id="demo"> 
    <input :value="text" ref="input"> 
    <button @click="update">OK</button> 
    <p id="result">{{text}}</p> 
</div> 
new Vue({ 
    el: '#demo', 
    data: function() { 
    return { 
     text: '' 
    }; 
    }, 
    methods: { 
    update: function() { 
     this.text = this.$refs.input.value; 
    } 
    } 
}); 

Es funktioniert, aber es funktioniert nicht gut skalieren, wenn es mehr Eingänge sind. Gibt es einen einfacheren Weg, dies zu erreichen, ohne $ Refs zu verwenden?

Antwort

2

können Sie ein Objekt verwenden und binden ihre Eigenschaften an die Eingänge. Dann können Sie in Ihrer update Methode die Eigenschaften für Anzeigezwecke auf ein anderes Objekt kopieren. Anschließend können Sie einen Deep Watcher festlegen, um die Werte für die Eingaben zu aktualisieren, wenn sich das Objekt ändert. Sie müssen beim Kopieren der Eigenschaften this.$set verwenden, damit die Änderung bei Vue registriert wird.

new Vue({ 
 
    el: '#demo', 
 
    data: function() { 
 
    return { 
 
     inputVals: { 
 
     text: '', 
 
     number: 0 
 
     }, 
 
     displayVals: {} 
 
    }; 
 
    }, 
 
    methods: { 
 
    update() { 
 
     this.copyObject(this.displayVals, this.inputVals); 
 
    }, 
 
    copyObject(toSet, toGet) { 
 
     Object.keys(toGet).forEach((key) => { 
 
     this.$set(toSet, key, toGet[key]); 
 
     }); 
 
    } 
 
    }, 
 
    watch: { 
 
    displayVals: { 
 
     deep: true, 
 
     handler() { 
 
     this.copyObject(this.inputVals, this.displayVals); 
 
     } 
 
    } 
 
    } 
 
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script> 
 
<div id="demo"> 
 
    <input v-model="inputVals.text"> 
 
    <input v-model="inputVals.number"> 
 
    <button @click="update">OK</button> 
 
    <input v-for="val, key in displayVals" v-model="displayVals[key]"> 
 
</div>

Wenn Sie ES2015 verwenden, können Sie Objekte direkt kopieren, so dass dies nicht so ausführlich:

new Vue({ 
 
    el: '#demo', 
 
    data() { 
 
    return { 
 
     inputVals: { text: '', number: 0 }, 
 
     displayVals: {} 
 
    }; 
 
    }, 
 
    methods: { 
 
    update() { 
 
     this.displayVals = {...this.inputVals}; 
 
    }, 
 
    }, 
 
    watch: { 
 
    displayVals: { 
 
     deep: true, 
 
     handler() { 
 
     this.inputVals = {...this.displayVals}; 
 
     } 
 
    } 
 
    } 
 
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script> 
 
<div id="demo"> 
 
    <input v-model="inputVals.text"> 
 
    <input v-model="inputVals.number"> 
 
    <button @click="update">OK</button> 
 
    <input v-for="val, key in displayVals" v-model="displayVals[key]"> 
 
</div>

+0

Danke, aber die gleiche Frage wie bei @DecadeMoon: Was, wenn ich die 'displayVals' von einer anderen Methode ändern möchte? Die Eingabefelder werden nicht automatisch aktualisiert. Wie bind 'displayVals' an' inputVals' mit scale? – niutech

+0

Meinst du, du willst "displayVals" nach dem Aufruf von 'update' dauerhaft an' inputVals' binden? – thanksd

+0

Ich möchte, dass die "Quelle der Wahrheit" 'displayVals' ist und ich möchte sie nicht nur durch Übermitteln des Formulars ändern, sondern auch von anderen Methoden. Aber dann möchte ich, dass die aktualisierten 'displayVals' automatisch in den Eingängen angezeigt werden, und der Benutzer kann sie bearbeiten und erst nach dem Klicken auf den Submit-Button sollten sie aktualisiert werden. Dies wäre ein einfacher Anwendungsfall für "V-Modell", wenn Werte bei jedem Tastendruck aktualisiert würden, was in meiner Situation nicht der Fall ist. – niutech

1

Sie können zwei separate Dateneigenschaften verwenden, eine für den Wert <input>, die andere für den festgeschriebenen Wert, nachdem auf die Schaltfläche OK geklickt wurde.

<div id="demo"> 
    <input v-model="editText"> 
    <button @click="update">OK</button> 
    <p id="result">{{text}}</p> 
</div> 
new Vue({ 
    el: '#demo', 
    data: function() { 
    return { 
     editText: '', 
     text: '' 
    }; 
    }, 
    methods: { 
    update: function() { 
     this.text = this.editText; 
    } 
    } 
}); 

Updated fiddle

+0

Danke, aber dann, wenn ich den 'Text' Wert aus einem anderen Verfahren, das Eingabefeld aktualisieren wird nicht geändert werden soll. Wie bindet man 'text' an' editText'? – niutech

+0

Verwenden Sie einen Watcher, um Änderungen an 'text' zu beobachten und' editText' auf den neuen Wert von 'text' zu setzen. –

+0

Und was ist, wenn ich 10s Eingänge habe? Dies ist viel mehr Standard als die Verwendung von $ refs. Gibt es keinen einfacheren Weg? – niutech

1

Mit einem leicht anderen Ansatz als die anderen Antworten Ich denke, Sie können etwas erreichen, das leicht sca ist label.

Dies ist ein erster Durchlauf, aber unter Verwendung von Komponenten könnten Sie Ihre eigenen Eingabeelemente erstellen, die genau dann übermittelt wurden, wenn Sie es wollten. Hier ist ein Beispiel eines Eingabeelements, das wie ein reguläres Eingabeelement funktioniert, wenn es außerhalb einer t-form Komponente liegt, aber nur v-model auf submit aktualisiert wird, wenn es sich in einem t-form befindet.

Vue.component("t-input", { 
    props:["value"], 
    template:` 
    <input type="text" v-model="internalValue" @input="onInput"> 
    `, 
    data(){ 
    return { 
     internalValue: this.value, 
     wrapped: false 
    } 
    }, 
    watch:{ 
    value(newVal){ 
     this.internalValue = newVal 
    } 
    }, 
    methods:{ 
    update(){ 
     this.$emit('input', this.internalValue) 
    }, 
    onInput(){ 
     if (!this.wrapped) 
     this.$emit('input', this.internalValue) 
    } 
    }, 
    mounted(){ 
    if(this.$parent.isTriggeredForm){ 
     this.$parent.register(this) 
     this.wrapped = true  
    } 
    } 
}) 

Hier ist ein Beispiel für t-form.

Vue.component("t-form",{ 
    template:` 
    <form @submit.prevent="submit"> 
     <slot></slot> 
    </form> 
    `, 
    data(){ 
    return { 
     isTriggeredForm: true, 
     inputs:[] 
    } 
    }, 
    methods:{ 
    submit(){ 
     for(let input of this.inputs) 
     input.update() 
    }, 
    register(input){ 
     this.inputs.push(input) 
    } 
    } 
}) 

Mit diesen Funktionen wird Ihre Arbeit sehr einfach.

<t-form> 
    <t-input v-model="text"></t-input><br> 
    <t-input v-model="text2"></t-input><br> 
    <t-input v-model="text3"></t-input><br> 
    <t-input v-model="text4"></t-input><br> 
    <button>Submit</button> 
</t-form> 

Diese Vorlage aktualisiert nur die gebundenen Ausdrücke, wenn auf die Schaltfläche geklickt wird. Sie können so viele t-inputs haben, wie Sie möchten.

Hier ist ein Arbeitsbeispiel. Ich habe t-input Elemente innerhalb und außerhalb des Formulars enthalten, so dass Sie sehen können, dass innerhalb des Formulars das Modell nur beim Senden aktualisiert wird und außerhalb des Formulars die Elemente wie eine typische Eingabe funktionieren.

console.clear() 
 
// 
 
Vue.component("t-input", { 
 
    props: ["value"], 
 
    template: ` 
 
    <input type="text" v-model="internalValue" @input="onInput"> 
 
    `, 
 
    data() { 
 
    return { 
 
     internalValue: this.value, 
 
     wrapped: false 
 
    } 
 
    }, 
 
    watch: { 
 
    value(newVal) { 
 
     this.internalValue = newVal 
 
    } 
 
    }, 
 
    methods: { 
 
    update() { 
 
     this.$emit('input', this.internalValue) 
 
    }, 
 
    onInput() { 
 
     if (!this.wrapped) 
 
     this.$emit('input', this.internalValue) 
 
    } 
 
    }, 
 
    mounted() { 
 
    if (this.$parent.isTriggeredForm) { 
 
     this.$parent.register(this) 
 
     this.wrapped = true 
 
    } 
 
    } 
 
}) 
 

 
Vue.component("t-form", { 
 
    template: ` 
 
    <form @submit.prevent="submit"> 
 
     <slot></slot> 
 
    </form> 
 
    `, 
 
    data() { 
 
    return { 
 
     isTriggeredForm: true, 
 
     inputs: [] 
 
    } 
 
    }, 
 
    methods: { 
 
    submit() { 
 
     for (let input of this.inputs) 
 
     input.update() 
 
    }, 
 
    register(input) { 
 
     this.inputs.push(input) 
 
    } 
 
    } 
 
}) 
 

 

 
new Vue({ 
 
    el: "#app", 
 
    data: { 
 
    text: "bob", 
 
    text2: "mary", 
 
    text3: "jane", 
 
    text4: "billy" 
 
    }, 
 
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script> 
 
<div id="app"> 
 
    <t-form> 
 
    <t-input v-model="text"></t-input><br> 
 
    <t-input v-model="text2"></t-input><br> 
 
    <t-input v-model="text3"></t-input><br> 
 
    <t-input v-model="text4"></t-input><br> 
 
    <button>Submit</button> 
 
    </t-form> 
 
    Non-wrapped: 
 
    <t-input v-model="text"></t-input> 
 
    <h4>Data</h4> 
 
    {{$data}} 
 
    <h4>Update Data</h4> 
 
    <button type="button" @click="text='jerome'">Change Text</button> 
 
</div>

Verwandte Themen