Guide to accessing component methods within slots using the Vue 3 Composition API

I have child components within a slot in a parent component and I am trying to call methods on them. Here are the steps I followed:

  • Use useSlots to retrieve the child components as objects
  • Expose the method in the child component using defineExpose
  • Call the method on the child component objects

However, I noticed that the method is not present on the object as expected.

For example:

// Parent.vue

<template>
    <div><slot/></div>
</template>

<script lang="ts" setup>
const slots = useSlots() as any;
const children = slots.default();

function callMethods() {
    console.log(children);
}
</script>
// SomeComponent.vue
<template>
    // ...
</template>

<script lang="ts" setup>
// ...

function methodToBeCalledByParent() {
    console.log(123);
}

defineExpose({
    methodToBeCalledByParent
});
</script>

In another part of the code, I placed this snippet:

<parent>
    <some-component/>
    <some-component/>
</parent>

Goal: Enable the callMethods function to call methodToBeCalledByParent in each respective some-component through the children object.

When the callMethods function is executed, there should be an array of two some-component instances printed in the console. However, the content of each child does not seem right, with many occurrences of null. Most importantly, the exposed methodToBeCalledByParent cannot be found in the object.

https://i.sstatic.net/E8I8GaZP.png

I have researched online and learned that the method can be called directly once the component object is retrieved. So I am unsure where the issue lies in my code. Can someone suggest the correct (or better) way to achieve this functionality?

Answer №1

While component instances may be accessible on vnode objects, it's important to note that this data is meant for internal use only and should not be relied upon in production environments.

To achieve this functionality, template refs need to be added to the vnodes from the slot. This can be accomplished within the render function as shown below:

setup() {
  const slots = useSlots();
  const slotRefs = reactive([]);

  return () => {
    const vnodes = slots.default?.() || [];
    slotRefs.length = vnodes.length;

    return vnodes.map((vnode, index) => 
      cloneVNode(vnode, { ref: (el) => slotRefs[index] = el })
    )
  }
}

This method is a simplified version of a scenario where children need conditional processing.

A similar approach can also be found in React, which borrowed the concept of Vue render function.

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

Can a type be created that resolves to either of two specific types?

If I have multiple functions that return either a number or a date, is there a way to define a type that encompasses both? For example, instead of: foo1(): number | Date {} foo2(): number | Date {} Can we do something like this: foo1(): NumberOrDate {} f ...

What could be the reason for certain Angular modules importing successfully while others fail to do so?

I am encountering an issue with a module that I am struggling to import. Using Typescript 2.7 and Node 10 The pxl-ng-security module is showing an error in both VSCode and VS2019. When hovering over it, error 2307 is displayed. Below is the import secti ...

Troubleshooting common issues while setting up React Native with TypeScript

After carefully following the steps outlined in this guide on configuring a React Native project using TypeScript: https://facebook.github.io/react-native/blog/2018/05/07/using-typescript-with-react-native, I encountered a total of fifteen errors from the ...

Error encountered while parsing Vue 3 with Eslint: Expected '>' but found '>'

Once I integrated Eslint into my project, I encountered a peculiar error in my .vue file specifically within the template section. The error message reads: Parsing error: '>' expected.eslint This issue arises within the following code block: ...

Click on an element in Angular to toggle it

A function in my codebase is responsible for toggling a specific section within a div element. Currently, there are a total of 3 sections available in the app. The functionality is implemented in the app.component.ts file: show = false; toggle() { ...

The Bootstrap-vue table stops displaying details when the data is refreshed

I am utilizing a bootstrap-vue table that is connected to a computed property pulling data from my vuex store. Each row contains a show_details button that expands a second row, following the guidelines here: The issue arises when there are changes in th ...

What steps can be taken to establish an array type that is limited to predefined values?

I am currently working on defining a type for an array that requires specific values to be present in a certain order at the beginning of the array. type SpecificArray = ('hello'|'goodbye'|string)[] // Current const myArray: SpecificAr ...

Prevent regex special characters in JavaScript while preserving the original string for keyword matching

As I develop my web page, I encountered an issue while trying to highlight text based on user input in the search box. My search algorithm matches each space-separated keyword, but ran into problems when including brackets in the search term. This caused a ...

Leveraging environment variables in Nuxt's nuxt.config.ts

nuxt.config.ts: env: { cmsUrl: process.env.CMS_URL || 'http://localhost:1337' } In order to define the CMS_URL as a system variable in production/staging mode, I have set it up this way. However, in dev mode, it defaults to using localhost. ...

What is the best way to remove query string parameters prior to running a function when a button is clicked?

I'm facing an issue trying to implement a button that filters events based on their tags. The problem arises when the tag value in the query string parameter does not clear when other buttons are clicked. Instead, the new filter tag value adds up with ...

What is the reason behind the occurrence of `(User & { _id: Schema.Types.ObjectId; }) | null` when calling findById?

Today marks my debut using typescript and mongoose. Here's a glimpse of what I've worked on. Type export interface User extends Document { _id: ObjectId; lastName: string; } Schema const userSchema = new Schema<User>({ lastName: { t ...

The function cannot be called on a type that does not have a callable signature. The specified type, 'number | Dispatch<SetStateAction<number>>', does not have any compatible call signatures

Currently, I am working on setting up state to be passed through context in React using hooks. However, when I attempt to use the dispatched state updater function, an error is thrown: Cannot invoke an expression whose type lacks a call signature. Type &a ...

Refreshing a value in the view at regular intervals using a filter in Vue

Trying to create a countdown timer with vue, but the view is not updating. Here are my app.js and index.html: var nowDate = new Date; var nextNewYearsEve = new Date(nowDate.getFullYear(), 11, 31, 23, 59, 59, 59); var timeLeftToNewYearsEve = nextNewYears ...

What is the best way to access data in a node.js application from IONIC typescript via a REST API?

Here is the structure of my service.ts: import { Injectable } from '@angular/core'; import {Http, Headers} from '@angular/http'; import 'rxjs/add/operator/map'; /* Generated class for the PeopleSearch provider. See http ...

Angular developers are struggling to find a suitable alternative for the deprecated "enter" function in the drag and drop CDK with versions 10 and above

By mistake, I was working on an older version of Angular in StackBlitz (a code-pane platform). I came across a function called enter on GitHub, but it didn't solve my issue. I was working on a grid-based drag and drop feature that allows dragging bet ...

Encountering issues importing Ace Document Object in a Vue webpack project?

In my Vue and Webpack project, I am trying to incorporate the Ace editor. My goal is to associate each file with a single instance of an Ace Document. To achieve this, I followed the default import method: import Ace from 'ace-builds' When atte ...

What is the best way to organize JSON data?

This is my method of retrieving JSON data. "wrk_hours": [{"opens_at": "09:00:00", "closes_at": "23:00:00", "day": "Tuesday"}, {"opens_at": "09:00:00", "closes_at": "23:00:00", "day": "Wednesday"}, {"opens_at": "09:00:00", "closes_at": "23:00:00", "day": " ...

Angular2 (RC5) global variables across the application

I am seeking a solution to create a global variable that can be accessed across different Angular2 components and modules. I initially considered utilizing dependency injection in my `app.module` by setting a class with a property, but with the recent angu ...

vee-validate: Personalized Validation Messages

I am currently working with Laravel 5.8 and Vue.js. My query pertains to displaying a custom error message for a specific rule in the Vee-Validate library. I have set a custom message for the "required" rule, but it is not showing up correctly. Instead of ...

Uncovering the perfect body proportions using Webpack and SystemJS

In the process of developing an Angular2 library that needs to work with both SystemJS and Webpack, I encountered a situation where I had to detect the height and width in pixels of the body tag to set dimensions for child tags. However, the behavior of An ...