I am relatively new to Vue and working on my first project. I'm trying to create a form with multiple child and grandchild components. I've run into a problem where I need to be able to generate multiple copies of a form. Therefore, I moved some data attributes up 1 level. Currently, the form is ApplicationPage.Vue > TheApplication.Vue > PersonalInformation.Vue > BaseInput.Vue. My problem is that I need to emit changes from PersonalInformation to ApplicationPage via TheApplication . I'm having a hard time figuring out how to handle this situation. I've been looking for a solution for Vue2 but haven't found a solution for Vue3.
ApplicationPage.vue
template <TheApplication :petOptions="petOptions" :stateOptions='stateOptions' v-model="data.primary" applicant="Primary"/> script data() { return { data: { primary: { personalInformation: { first_name: "", middle_name: "", last_name: "", date_of_birth: "", phone: null, email: "", pets: "", driver_license: null, driver_license_state: "", number_of_pets: null, additional_comments: "" }, }, }, } },
TheApplication.Vue
<personal-information :petOptions="petOptions" :stateOptions='stateOptions' :personalInformation="modelValue.personalInformation" @updateField="UpdateField" />
methods: { UpdateField(field, value) { this.$emit('update:modelValue', {...this.modelValue, [field]: value}) },
Personal information.vue
<base-input :value="personalInformation.first_name" @change="onInput('personalInformation.first_name', $event.target.value)" label="First Name*" type="text" class="" required/>
methods: { onInput(field, value) { console.log(field + " " + value) // this.$emit('updateField', { ...this.personalInformation, [field]: value }) this.$emit('updateField', field, value) }, }
P粉0378809052023-11-04 14:55:06
For anyone who doesn't want to chain event emitting, there is a parent object on the child object which can also be used to emit events. Be sure to register the launch in the parent to avoid warnings in the console.
Call the direct parent's $emit
here.
Child.vue
<input @input="$parent.$emit('custom-event', e.target.value) />
Or how to use:
<input @input="handleInput" />
export default { methods: { handleInput(e) { this.$parent.$emit('custom-event', e.target.value) } } }
Since it is the parent that signals the ancestor, declare the emission here. For , just use the
defineEmits()
method to declare emits. See Documentation.
Parent.vue
<Child /> <!-- No need to listen to the event here -->
export default { emits: ['custom-event'] // Register the emits }
If using <脚本设置>
<script setup> defineEmits(['custom-event']) // Register the emits </script>
Then listen to the event in the grandparent component.
GrandParent.vue
<Parent @custom-event="doSomething()" /> <!-- The event is being listened to in the grandparent component -->
P粉8422150062023-11-04 12:19:54
This is how I do it: codesandbox< /a>
Emits accepts only two parameters, the emitted name and the emitted value. If multiple values are emitted, they must be emitted as a single object. In my solution, the grandchild component emits the field name and value as a single object
grandson
<input :value="personalInformation.first_name" @input="onInput('first_name', $event.target.value)" ... >
onInput(field, value) { this.$emit("update-field", { field: field, value: value }); },
The child object captures and re-eits, but first takes care to emit in the format expected by the parent component (it requires the entire data.primary
object because that's what is set to the v model )
child
<grandchild :personalInformation="modelValue.personalInformation" @updateField="UpdateField" />
UpdateField({ field, value }) { const newVal = this.modelValue; newVal.personalInformation[field] = value; this.$emit("update:modelValue", newVal); }
Then the parent component will automatically receive and update the v-model data.primary
object.
Or , I must mention that you can always use Pinia, the official state management library for Vue (to save some state in one component and read the same from any other component status). There's certainly a learning curve, but it's definitely worth learning and is designed to simplify this type of situation.