17

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')
0

7 Answers 7

37

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

Parent

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

<script>
const myChild = ref(null);

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

Child Component

<template>
  ...
</template>

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

defineExpose({
  childMethod
});
</script>
Sign up to request clarification or add additional context in comments.

2 Comments

Check my comment below for how to define expose in a export default. stackoverflow.com/a/75832706/6342456
This appears to be missing a .value in the myChild.childMethod() invokation. @CoderMeng has the correct syntax.
11

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>

Comments

3

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

Comments

2

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 ;-)

Comments

1

In Vue 3, when using syntax API to call a child method from its own parent, two pitfalls are often easy to fall into: 1) ‘value’ attribute of the child component reference is missed in the parent component script. 2) the child function is not exposed to external by using defineExpose. See How to call a child component’s function from the parent in Vue

Comments

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.

Comments

-1

Need to keep in mind that if your child component are being iterated through an array, passInSomeMagic will be an array. So you have to call your child component's function something like this:

if (Array.isArray(passInSomeMagic.value)) {
    for (let idx = 0; idx < FilterItemsComponent.value.length; idx++) {
      passInSomeMagic.value[idx].childFunction();
    }
  } else passInSomeMagic.value.childFunction();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.