Suppose I had the following pattern in my vue.js application:
Form.vue:
<template>
<form>
<page-1 v-if="step === 1" :firstName="firstName" :lastName="lastName" @submit="step = 2"></page-1>
<page-2 v-if="step === 2" :email="email" @submit="step = 3"></page-2>
<page-3 v-if="step === 3" :comments="comments" @submit="submit()"></page-3>
</form>
</template>
<script>
import Page1 from './Page1.vue';
import Page2 from './Page2.vue';
import Page3 from './Page3.vue';
export default {
components: {
Page1,
Page2,
Page3
},
data() {
return {
firstName: '',
lastName: '',
email: '',
comments: '',
step: 1
}
},
methods: {
submit() {
// submit the form
}
}
}
</script>
<style>
</style>
Page1.vue:
<template>
<label>First Name:</label>
<input type="text" v-model="firstName"></input>
<label>Last Name:</label>
<input type="text" v-model="lastName"></input>
<button @click="$emit('submit')">Next</button>
</template>
<script>
export default {
props: {
firstName: '',
lastName: ''
}
}
</script>
<style>
</style>
Page2.vue:
<template>
<label>Email:</label>
<input type="email" v-model="email"></input>
<button @click="$emit('submit')">Next</button>
</template>
<script>
export default {
props: {
email: ''
}
}
</script>
<style>
</style>
Page3.vue:
<template>
<label>Comments:</label>
<textarea v-model="comments"></textarea>
<button @click="$emit('submit')">Submit</button>
</template>
<script>
export default {
props: {
comments: ''
}
}
</script>
<style>
</style>
Essentially, it's a form with three pages. The parent component is the form and each page is a child component. The parent component keeps track of the form fields with its data and passes them to each page by props. But this is a bad design because I'm mutating the props in each child component by assigning them to v-model on each input.
Most solutions to this problem I've seen on Google suggest using computed properties but because I'm using v-model, I need to maintain two-way binding and computed properties seem one-way only. So I'm wondering if the following is a common pattern for resolving this problem which is considered a good design:
Form.vue:
<template>
<form>
<page-1 v-if="step === 1" :firstName="firstName" :lastName="lastName" @first-name-changed="val => firstName=val" last-name-changed="val => lastName=val" @submit="step = 2"></page-1>
<page-2 v-if="step === 2" :email="email" @email-changed="val => email=val" @submit="step = 3"></page-2>
<page-3 v-if="step === 3" :comments="comments" @comments-changed="val => comments=val" @submit="submit()"></page-3>
</form>
</template>
<script>
import Page1 from './Page1.vue';
import Page2 from './Page2.vue';
import Page3 from './Page3.vue';
export default {
components: {
Page1,
Page2,
Page3
},
data() {
return {
firstName: '',
lastName: '',
email: '',
comments: '',
step: 1
}
},
methods: {
submit() {
// submit the form
}
}
}
</script>
<style>
</style>
Page1.vue:
<template>
<label>First Name:</label>
<input type="text" v-model="firstNameData"></input>
<label>Last Name:</label>
<input type="text" v-model="lastNameData"></input>
<button @click="$emit('submit')">Next</button>
</template>
<script>
export default {
props: {
firstName: '',
lastName: ''
},
data() {
return {
firstNameData: '',
lastNameData: ''
}
},
watch: {
'firstNameData': function() {
this.$emit('first-name-changed', this.firstNameData);
},
'lastNameData': function() {
this.$emit('last-name-changed', this.lastNameData);
}
},
created() {
this.firstNameData = this.firstName;
this.lastNameData = this.lastName;
}
}
</script>
<style>
</style>
Without repeating the same pattern in the other two child components, the idea is to copy the values of the props to data variables in the child components, bind the data variables to the inputs, watch for changes in the data variables and emit events back up to the parent when they change. These emits would come with the new values and the parent would assign these new values to its data variables.
I don't need to worry about the props passed to each child component changing dynamically. The only reason I want to pass them down to the child components is because the user might want to re-load the form from a draft (otherwise, there would be no need for props at all).
My question is: is this a good design pattern?
Aucun commentaire:
Enregistrer un commentaire