Using Composition API to call a method on a child component

In my current project, I am facing a challenge with a parent component needing to call a method from one of its child components:

<template>
  <div>
    <button @click="callChildMethod">
    <child-component ref="child" />
  </div>
</template>
<script>
  setup(props) {
    const child = ref(null)
    const callChildMethod = () => {
      child.doSomething()
    }

    return {
      child,
      callChildMethod
    }
  }
</script>
  

The child component contains a method named doSomething:

const doSomething = () => { console.log('calling method....') }

My project is based on VueJS3 and the Composition API, and I tried using a template ref to access the method in the child component. However, I am facing issues and can't figure out what I'm missing. If anyone has any insights or suggestions, I would greatly appreciate it. Thank you!

Answer №1

Just a heads up, if you're using the <script setup> (Composition API), you'll need to incorporate the defineExpose function.

Check out more details here: https://v3.vuejs.org/api/sfc-script-setup.html#defineexpose

Here's an example of how to use it in a parent component:

<script setup>
...
const children = ref();

children.value.doSomething();
</script>

<template>
  <ChildrenComponent ref="children" />
</template>

And in the ChildrenComponent:

<script setup>
...
function doSomething(){
  console.log(1);
}

defineExpose({
  doSomething,
});

</script>

<template>
  <div>123</div>
</template>

Answer №2

Make sure to include the value field in your ref, like this:

 const callChildMethod = () = {
  child.value.doSomething()
}

https://codesandbox.io/s/amazing-cori-5hgi9?fontsize=14&hidenavigation=1&theme=dark

If you are using the script setup syntax to define the child component, you should utilize defineExpose to make the method accessible externally

<script setup>

function doSomething(){
  //......
}

defineExpose({
  doSomething,
});

</script>

Parent :

<template>
  <div>
    <button @click="callChildMethod">
    <child-component ref="child" />
  </div>
</template>
<script>
  setup(props) {
    const child = ref(null)
    const callChildMethod = () => {
      child.doSomething()
    }

    return {
      child,
      callChildMethod
    }
  }
</scrip>

or

<template>
  <div>
    <button @click="callChildMethod">
    <child-component ref="child" />
  </div>
</template>
<script setup>

    const child = ref(null)
    const callChildMethod = () => {
      child.doSomething()
    }


</scrip>

Answer №3

When I encountered an error with the ref method, I discovered an alternative approach that worked well for me. By using watch for a property set by a reactive variable in the parent component and emitting back the results, I found a solution that provided more control:

Child Component:

const props = defineProps({
  callRequested: {
    type: Boolean,
  },
});
function myFunc() {
  let result = false;
  // Perform necessary actions
  return result;
}
const emit = defineEmits(['funcResult']);
watch(
  () => props.callRequested,
  (newVal) => {
    console.log(`newVal is: ${newVal}`);
    if (newVal)
      emit('funcResult', myFunc());
  }
)

Parent Component:

<template>
  <div>
    <button @click="callChildMethod">
    <child-component 
     :call-requested="state.callRequested" 
     :@func-result="funcResult"
    />
  </div>
</template>
<script setup>
const state = reactive({
  callRequested: false,
});
function callChildMethod() {
  state.callRequested= true;
}
function funcResult(param) {
  state.callRequested = false;  // Reset for the next call
  // Perform actions in parent component based on the function result
}
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error message: "When namedPlaceHolder parameter is disabled, bind parameters must be in the form of an

Currently revamping my query due to a crucial API redesign. With the presence of a "file" as multipart/form-data, I found the need for a form handler since NextJS lacked one. After some workarounds with "multiparty", now I can successfully parse the incomi ...

Develop a Rails object using AJAX and JavaScript

Within a music application built on Rails, I am attempting to monitor plays for tracks by artists. This involves creating a unique play object each time a visitor plays a track on the site. These play objects are assigned their own distinct IDs and are ass ...

Jsoup encounters a complication due to lack of support for Javascript

1http://www.biletix.com/search/TURKIYE/en#!city_sb:İstanbul,date_sb:today Trying to access an element from the provided link results in a message about Javascript not being found. It suggests enabling Javascript and then abruptly closes. As I plan to mi ...

Having trouble getting JavaScript to work when returned via AJAX

After triggering a lightbox by clicking on a business name, I encountered an issue when trying to replicate the same functionality using AJAX. The lightbox fails to show up. Can anyone provide assistance? The following code represents a 3rd party publishe ...

Oops! Before proceeding, make sure to call TestBed.initTestEnvironment() first

Currently, I am experimenting with testing a service in Angular. Below is the code snippet I am working on: describe('AddressService', () => { let service: AddressService; let injector: TestBed; let httpTestingController: HttpTesting ...

Directing a user in real-time to the login portal

In my Vue.js application, certain routes require user authentication while others, like the login page, are public. created() { let context = this; context.axios.create({withCredentials: true}).get(`${context.$store.getters.getApiUrl}/session/`).t ...

Toggle the ASP validation control using JavaScript

I am looking to control the validation of my form using JavaScript. When a user clicks on a radio button in a list (yes or no), 2-3 rows are displayed. If the user selects "Yes," they must enter input into a textbox in one of those rows. To enforce this, ...

The POST request to the localhost API endpoint resulted in a 404 Not Found error

Whenever I try to send a POST request to "/api/auth/signup" in my JavaScript application, I keep getting a 404 Not Found error. My goal is to create a MERN application for a Modern Real Estate Marketplace. This is the code snippet causing the is ...

What is causing the failure of success function commands to be executed?

Currently, I am facing some inconsistencies between my locally hosted app on WAMP (working perfectly) and the deployed version of my app. In an attempt to resolve this issue, I am working with CodeIgniter and jQuery AJAX. As part of my troubleshooting proc ...

The Importance and Purpose of Incorporating a Callback

Understanding asynchronous operations and callbacks has been a challenge for me. To improve my familiarity with these concepts, I've been studying code examples that utilize them. However, there's one aspect of this specific code snippet that con ...

Heroku Foreman unexpectedly stops while using Express.js bodyParser() function

After running foreman start, the following message is displayed: > foreman start 20:38:55 web.1 | started with pid 3896 20:38:55 web.1 | Development 20:38:56 web.1 | connect.multipart() will be removed in connect 3.0 20:38:56 web.1 | exited with co ...

I have implemented a code snippet that verifies if the incoming week aligns with the existing week, triggering an alert accordingly

One of the challenges I faced was checking if a newly created week matched with an existing one, and then displaying an alert. Here's how I approached it: $scope.addWeek = function(type,newWeek,index){ var c = $scope.weekList.length + 1; var ...

What is the best way to eliminate the nesting in this ternary operation?

Object.values(filter).filter(item => (Array.isArray(item) && item.length > 0) || (typeof item === "boolean" && item === true) || (item !== null)).length ? filterIcon : unFilledIcon In this code, I aim to simplify the nested ternary operator and ...

The Angular directive ng-model is not able to return a value

I'm currently troubleshooting an issue with the filters in an older project. Here's the HTML snippet: <input type="text" class="form-control" ng-model="FilterEventsEdit" ng-change="FilterEvents()" ...

Strange behavior: JS object values disappear when accessed statically

I'm feeling puzzled. The issue at hand is that an object seems to lose its values within a loop based on the method of access. When accessed through variables, everything appears to be in order. However, when using static expressions identical to the ...

The environment variable process.env.variable works perfectly fine during local development, however, it seems to malfunction once the application is deployed to Heroku within

Currently, I am utilizing nuxt.js and attempting to display images dynamically. To achieve this, I have implemented the BASE_URL variable within the .env file, allowing me to access image files based on the set BASE_URL in my local environment. .env file ...

jQuery can be utilized to generate repeated fields

$(document).ready(function(){ $('#more_finance').click(function(){ var add_new ='<div class="form-group finance-contact" id="finance_3"><div class="col-sm-9"><label for="firstName" class="contro ...

Ensure you wait for the next tick before making any assertions using vitest

Within a composable, I have implemented a reactive primitive foo and a function onFooChange. There is a watcher in this composable that monitors changes to foo and calls onFooChange upon any change. I am looking to write a unit test to verify the executio ...

Is there a way to verify if both the username and email have already been registered?

I've exhausted multiple methods attempting to solve this issue, but every attempt falls short. My most recent strategy involved creating two "findOne" functions, however, even that proved unsuccessful. const checkUser = registerLogin.findOne ...