6

I can't call child component method in parent component in Vue3

In Vue2, I can call child component method like this

this.$root.$refs.ChildComponent.methodName()

But in Vue3, I receive a error like this

runtime-core.esm-bundler.js:218 Uncaught TypeError: Cannot read properties of undefined (reading 'methodName')
General Grievance
  • 4,555
  • 31
  • 31
  • 45
Khang
  • 69
  • 2
  • 9

5 Answers5

11

defineExpose could do the magic. You could do something like this:

Parent

<template>
  <ChildComponent ref="myChild"/>
</template>

<script>
const myChild = ref(null);

function() {
  myChild.childMethod();
}
</script>

Child Component

<template>
  ...
</template>

<script setup>
function childMethod() {
 // do something
}    

defineExpose({
  childMethod
});
</script>
Darryl Noakes
  • 2,207
  • 1
  • 9
  • 27
nocrash9000
  • 136
  • 3
  • Check my comment below for how to define `expose` in a `export default`. https://stackoverflow.com/a/75832706/6342456 – Maka Mar 24 '23 at 10:57
  • This appears to be missing a `.value` in the `myChild.childMethod()` invokation. @CoderMeng has the correct syntax. – sxc731 Aug 31 '23 at 07:49
6

defineExpose can expose child component props and methods

// in Parent
<template>
<ChildComponent ref="myChild"/>
</template>

<script setup>
const myChild = ref(null);

function testCall() {
  myChild.value.childMethod();
}

</script>
// ChildComponent
<template> ... </template>
<script setup>

function childMethod() {
 // do something
}    

defineExpose({
        childMethod
    });
</script>
CoderMeng
  • 739
  • 1
  • 6
  • 8
1

Depending on setup and versions some of the suggestions may not work for everyone. I have found this useful and works for me.

This will allow you to call any Child's "named" mathod from your Root component. You can pass in some data as well as on example below.

Child component

Expose your method using expose list. Accepts array of methods.

<template>... your child component...</template>

<script>
export default {
expose: ['doSomeMagic'],
methods: {
    dosomeMagic(params){
        console.log("Passed in params", params);
    }
}

</script>

Root App.vue

Import your component and add ref with some magic per example: ref="passInSomeMagic"

<template>
    <DoMagicComponent :bookmark="device" ref="passInSomeMagic"/>
</template>

<script>
import DoMagicComponent from "./components/DoMagicComponent";
import { ref } from 'vue';
const passInSomeMagic = ref(0);
export default {
name: "App",
  components: {
    DoMagicComponent
},
methods: {
    helloWorld(){
        this.$refs.passInSomeMagic.dosomeMagic({"hi", "test 1234"});
    }
}

</script>

More details on expose can be found here: https://vuejs.org/guide/essentials/template-refs.html#refs-inside-v-for

Maka
  • 371
  • 3
  • 14
0

You might want to pass in a prop to the child, and react to a change-event by calling the method. This could look something like this:

<!-- Parent.vue -->
<script setup>
/* declare invokeChildMethod */
</script>

<template>
  <Child :prop="invokeChildMethod" /> 
</template>

As can be seen in the code below, when the variable (here called invokeChildMethod) changes (in the parent), an event for the child will be fired.

Here's a resource on watching props in Vue3.

STh
  • 746
  • 9
  • 24
0

If not using script setup it is directly callable at the parent component by

this.$refs.childComponent.methodToInvoke();

Otherwise if a script setup section must/should be declared at the child component, I learned that I had to declare it like this inside a defineComponent section.

<script>
  import {defineComponent, defineExpose} from 'vue';
  
  export default defineComponent({
  
    setup() {
      // context now contains this  
      defineExpose({
        methodToInvoke: this.methodToInvoke
      });
    },

    methods: {
      methodToInvoke(): {
      ...
      }
    }
  });
</script>

It cannot be declared as a separate section in a SFC (single file component) when having the component also declared in a <script> section

<script setup>
  import {defineExpose} from 'vue';
  
  defineExpose({
    methodToInvoke: this.methodToInvoke
  });
</script>

since the this context is not given here.

If I got something wrong please let me know since I am not a vue3 specialist and rather just beginning with vue3 ;-)

Dirk Schumacher
  • 1,479
  • 19
  • 37