vue.jscomponentsvuejs3emitvue-props

Passing data to an ancestor component vue3


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.


Solution

  • 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