'What's the best way to trigger a child emit from the parent component?

Right now I'm passing a trigger prop from the parent to child component, which triggers the emit from the child to the parent.

parent component:

<form @submit.prevent="state.store=true" method="post" enctype="multipart/form-data">

    <child-component :triggerEmit=state.store @emitSomething="getSomething()"/>

child component:

const emit = defineEmits([
    'emitBody'
])

watchEffect(async () => {
    if (props.triggerEmit) {
        emit('emitSomething', value)
    }
})

This gets confusing quickly, if the components grow in size and I was wondering if there is a simpler way to trigger child emits from the parent, since this seems to be a common use case.

Edit:

Trying to trigger the child method directly from the parent (not working).

child:

const childMethod = () => {
    console.log('check')
}

parent:

html:

  <child ref="childRef"/>

script setup:

const childRef = ref()

childRef.value.childMethod()

Page throws error:

Cannot read properties of undefined (reading 'childMethod')


Solution 1:[1]

As per my understanding you want to access multiple child component methods/properties from the parent component. If Yes, you can achieve that by create a ref and access the methods.

In template :

<!-- parent.vue -->
<template>
    <button @click="$refs.childComponentRef.childComponentMethod()">Click me</button>
    <child-component ref="childComponentRef" />
</template>

In script :

With Vue 2 :

this.$refs.childComponentRef.childComponentMethod( );
   

With Vue 3 Composition Api :

setup( )
{
    const childComponentRef = ref( );

    childComponentRef.value.childComponentMethod( )

    return {
       childComponentRef
    }
 }  

Solution 2:[2]

In this case, the parent's trigger is effectively querying the child for its event data so that it could call getSomething() on it. The parent already owns getSomething(), so it really only needs the child data.

Another way to get that data is to use v-model to track the child data:

  1. In the child component, implement v-model for a prop (a string for example) by declaring a modelValue prop and emitting an 'update:modelValue' event with the new value as the event data:
<!-- ChildName.vue -->
<script setup>
defineProps({ modelValue: String })
defineEmits(['update:modelValue'])
</script>

<template>
  <label>Name
    <input type="text" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
  </label>
</template>
  1. In the parent, add a reactive object, containing a field for each child's v-model:
<!-- ParentForm.vue -->
<script setup>
import { reactive } from 'vue'

const formData = reactive({
  name: '',
  age: 0,
  address: {
    city: '',
    state: '',
  },
})
</script>

<template>
  <form>
    <child-name v-model="formData.name" />
    <child-age v-model="formData.age" />
    <child-address v-model:city="formData.address.city" v-model:state="formData.address.state" />
    <button>Submit</button>
  </form>
</template>
  1. Now, the parent can call getSomething() on each field upon submitting the form:
<!-- ParentForm.vue -->
<script setup>
import { toRaw } from 'vue'
?
const getSomething = field => {
  console.log('getting', field)
}

const submit = () => {
  Object.entries(toRaw(formData)).forEach(getSomething)
}
</script>

<template>
  <form @submit.prevent="submit">
    ?
  </form>
</template>

demo

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rohìt Jíndal
Solution 2