Passing data to an ancestor component vue3

Viewed 29

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,

  1. A multi step form
  2. One step includes a nested component that needs to pass data up to the root ancestor
  3. I cannot seem to access/emit data from setup() back up to the ancestor element

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.

1 Answers

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>

demo

Related