Emit event input from child component to parent in Nuxt JS Composition API

Viewed 886

I'm new to Vue 3 and Nuxt JS Composition API (TypeScript). I'm making a simple form/input component which I expected the behavior to be when used in a Page, passing down data from parent and from the input of child component, every changes to input value will be emitted to parent and will be updated in parent's template. But it seemed that the parent didn't 'catch' the event emitted. Below is the project structure.

|components
|----/forms
|-------- vi-form.vue
|-------- vi-input.vue
|pages
|----test.vue
|...everything else is as same as normal Nuxt JS Composition API project

components\forms\vi-input.vue file

<template lang="pug">
    div()
        input( v-model.trim="_model" :required="_isRequired" )
</template>

<script lang="ts">
import { computed, defineComponent, inject, ref, useContext, watch } from '@nuxtjs/composition-api'

export default defineComponent({
    props: {
        isRequired: {
            type: Boolean
        },
        label: {
            type: String
        },
        model: String
    },
    setup(props, { emit }) {
        const _isRequired = computed(() => {
            return props['isRequired'] || false
        })

        const _label = computed(() => {
            return props['label'] || ''
        })

        const _model = computed({
            get():string {
                if (props['model'] != undefined)
                    return props['model']
                return ''
            },
            set(value: string) {
                emit('update:model', value)
            }
        })

        return { _isRequired, _label, _model }
    },
})
</script>

components\forms\vi-form.vue

<template lang="pug">
    form(@submit.prevent='_submitCb')
        slot
        div
            button(type='button' @click='_resetValue = !_resetValue')
                span()
                | {{ _cancelLbl }}
            button(type='submit')
                span()
                | {{ _submitLbl }}
</template>

<script lang="ts">
import { computed, defineComponent, provide, ref } from '@nuxtjs/composition-api'

export default defineComponent({
    props: {
        submitCb: {
            type: Function
        },
        submitLbl: {
            type: String
        },
        cancelCb: {
            type: Function
        },
        cancelLbl: {
            type: String
        },
        resetForm: {
            type: Boolean
        }
    },
    setup(props) {
        const _submitCb = computed(() => {
            if (!props['submitCb']) {
                return () => {
                    console.log('default submit callback')
                }
            }

            return props['submitCb']
        })

        const _submitLbl = computed(() => {
            return props['submitLbl'] || 'Submit'
        })

        const _cancelCb = computed(() => {
            if (!props['cancelCb']) {
                return () => {
                    console.log('default cancel callback')
                }
            }

            return props['cancelCb']
        })

        const _cancelLbl = computed(() => {
            return props['cancelLbl'] || 'Cancel'
        })

        const _resetForm = computed(() => {
            if (props['resetForm'] && (props['resetForm'] == true || props['resetForm'] == 'true'))
            {
                return true
            }

            return false
        })

        const _resetValue = ref(false)

        provide('resetValue', _resetValue)

        return { _submitCb, _submitLbl, _cancelCb, _cancelLbl, _resetForm, _resetValue }
    },
})
</script>

pages\test.vue

<template lang="pug">
    div(class="w-50 m-auto")
        vi-form(:submitCb='submit' submitLbl='Submit' class="border")
            vi-input(label="Fullname" :model="fakeData.full_name")

        div(class="p-2 border")
            h2() Form data
            p() Fullname: {{ fakeData.full_name }}
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from '@nuxtjs/composition-api'

export default defineComponent({
    setup() {
        const fakeData = reactive({
            full_name: 'John Doe',
        })
        const submit = () => {
            console.log(fakeData.full_name)
        }

        return { submit, fakeData }
    },
})
</script>

My problem it I can not emit the event update:value to parent, I tried emit with input but still it seem that the parent page doesn't handle this event. I also tested that if I put an input box in parent template and assign `v-model='fakeData' on it, I can alter the input's value in parent and the child's input value will also changed, but not the other way around.

Another try is that if I explicitly write like this

vi-input(label="Fullname" :model="fakeData.full_name" @update.value='v => fakeData = v')

then it works, I can change the parent's data from the child component but this method of explicitly adding @update.value in the component is not wrote in anywhere of the Vue documents that I read.

I've read articles about passing input data between child and parent component and they all showed this is kind of the correct way to do it but I still don't understand why my code not working. Vue 3 document , Vue 3 Data down Event up

Could anyone help me on this problem?

0 Answers
Related