Reputation: 2958
I have a form which contains name and address components. In the parent's page I have a submit button. I can send data from the parent to the children using props. Now I am trying to get the children's values from the parent's form. And I want to validate child fields from the parent's form. How to acheive this?
Here is my form structure.
parent.vue
<form @submit.prevent="handleSubmit">
<name-fields :user='user'></name-fields>
<address-fields :address='address'></address-fields>
<button>Register</button>
</form>
<script>
export default {
data () {
return {
user: {
firstName: 'Raja',
lastName: 'Roja',
},
address: {
doorNo: '11',
state: 'KL',
country: 'IN',
},
submitted: false
}
},
components: {
'name-fields': cNameFields,
'address-fields': cAddressFields,
},
}
</script>
cNameFields.vue
<template>
<div>
<div class="form-group">
<label for="firstName">First Name</label>
<input type="text" v-model="user.firstName" v-validate="'required'" name="firstName" class="form-control" :class="{ 'is-invalid': submitted && errors.has('firstName') }" />
<div v-if="submitted && errors.has('firstName')" class="invalid-feedback">{{ errors.first('firstName') }}</div>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" v-model="user.lastName" v-validate="'required'" name="lastName" class="form-control" :class="{ 'is-invalid': submitted && errors.has('lastName') }" />
<div v-if="submitted && errors.has('lastName')" class="invalid-feedback">{{ errors.first('lastName') }}</div>
</div>
</div>
</template>
<script>
export default {
name: 'name',
props: {
user: Object,
submitted : Boolean
},
</script>
Currently getting this output:
What I want to do:
Upvotes: 0
Views: 2966
Reputation: 7177
You are passing objects as props to your children, which are passed by reference in JavaScript. From the Vue docs ..
Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child component will affect parent state.
This means that you're already getting the children's values in the parent and you can access them in the parent through this.user.firstName
,this.user.lastName
, this.address.doorNo
, etc. If this isn't the intended behavior and you want to keep your parent's data isolated then you should look into deep cloning your objects.
If you want to expose your validation errors from your child components to the parent you can look into Scoped Slots. So you may do something like this ..
parent.vue
<form @submit.prevent="handleSubmit">
<name-fields :user='user'>
<span slot="firstName" slot-scope="{validationErrors}" style="color:red">
{{validationErrors.first('firstName')}}
</span>
<span slot="lastName" slot-scope="{validationErrors}" style="color:red">
{{validationErrors.first('lastName')}}
</span>
</name-fields>
<address-fields :address='address'>
<span slot="doorNo" slot-scope="{validationErrors}" style="color:red">
{{validationErrors.first('doorNo')}}
</span>
<span slot="state" slot-scope="{validationErrors}" style="color:red">
{{validationErrors.first('state')}}
</span>
<span slot="country" slot-scope="{validationErrors}" style="color:red">
{{validationErrors.first('country')}}
</span>
</address-fields>
<button>Register</button>
</form>
cNameFields.vue
<template>
<div>
<div class="form-group">
<label for="firstName">First Name</label>
<input type="text" v-model="user.firstName" v-validate="'required'" name="firstName" class="form-control" :class="{ 'is-invalid': submitted && errors.has('firstName') }" />
<slot name="firstName" :validationErrors="errors"></slot>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" v-model="user.lastName" v-validate="'required'" name="lastName" class="form-control" :class="{ 'is-invalid': submitted && errors.has('lastName') }" />
<slot name="lastName" :validationErrors="errors"></slot>
</div>
</div>
</template>
This is a great video that explains how scoped slots work.
Upvotes: 1
Reputation: 31
Use this.$emit https://v2.vuejs.org/v2/api/#vm-emit and also use watch https://v2.vuejs.org/v2/api/#vm-watch
So in child component you should watch for changes in user.firstName and user.lastName. Call emit in the watch and get the value in parent. Don't forget to also emit the this.errors bag which comes from vee-validate.
Hope this will help you :)
Upvotes: 1