I have a multi-step form in Vue3 that has the following structure:
<Formroot />
...
<formPage2 />
...
<postcodeWidget />
I have a data structure in my formRoot that holds all the field values from the child components and then uses them to make an external API call and present a result.
I use Props to pass the data down to the child components and then emit from the children to the parent.
The issue is, my autocomplete widget - which pulls from an external api - does all the autocomplete in the setup()
function. I cannot figure out the best way to communicate input from that widget back up to the formRoot component.
I tried emitting from the widget but I can't access the instance from within setup, and I can't seem to access the data from setup variables within an instance method.
For example, I have a function called changePostcode that fires on input to the field:
methods: {
changePostcode(e){
//I have tried calling the input event:
this.$emit('update:postcode', e.target.value)
//I have tried accessing my setup variable:
this.$emit('update:postcode', this.selectedPostcode) //or postcode.value this is the actull value I want to emit.
//these dont work.They return nothing.
},
}
my selectedPostcode variable is set in the setup() function as follows:
setup() {
...
let selectedPostcode = ref('')
let searchTerm = ref('')
...
// searchTerm is used in a filter with data from an external API to offer suggestions. This is the ultimate source of the "location" object
const selectPostcode = (location) => {
selectedPostcode.value = location.postcode
searchTerm.value = location.locality
}
return {
searchTerm,
...
selectPostcode,
selectedPostcode,
...
}
}
I have a locality and a postcode variable because I want to populate the input with a "locality" that includes the full name of the suburb while I want to emit only the post/zip code.
My setup does a bunch of other work including calling and api for a list of suburb and filtering on user input to make suggestions. That all works fine.
In summary,
What is the right way to do this? It seems like it should be a pretty common use case.
I looked into provide/inject
as well but I also couldn't understand how to send data back up to the ancestor only down to the child.
The ancestor could provide
a function (e.g., a setter) that the nested component could inject
to communicate a value back to the ancestor:
// RootAncestor.vue
<script setup>
import { ref, provide } from 'vue'
const postCode = ref('initial value')
const setPostCode = value => {
postCode.value = value
}
provide('setPostCode', setPostCode)
</script>
// NestedComponent.vue
<script setup>
import { inject } from 'vue'
const setPostCode = inject('setPostCode')
const save = () => {
setPostCode('12345')
}
</script>