Is there a way to access and invoke a exposed function of a Vue component within a default slot?

Exploring the realms of a vue playground.

The functions interfaceFunction in both ChildA and ChildB are exposed.

In App, these functions can be called by obtaining references to the components that expose them. This allows direct function calls from within App.

For Container to access and call these functions from its children in the default slot, how can it obtain references to the components and invoke the functions?

Code snippet from App.vue:

<script setup>
import { ref} from 'vue'

import Container from './Container.vue'
import ChildA from './ChildA.vue'
import ChildB from './ChildB.vue'

const childa = ref(null)

function callInterfaceFunction() {
    childa.value.interfaceFunction()
}
</script>

<template>
    <button @click="callInterfaceFunction">Call from App</button>

    <Container>
        <ChildA ref="childa"/>
        <ChildB />
    </Container>
</template>

Code snippet from Container.vue:

<script setup>
import { useSlots} from 'vue'

const slots = useSlots()

function callInterfaceFunction() {
  const children = slots.default()

  for ( const child of children ) {
    child.interfaceFunction()
  }
}
</script>

<template>
  <button @click="callInterfaceFunction">Call from Container</button>

  <slot />
</template>

Code snippet from ChildA.vue:

<script setup>

function interfaceFunction() {
  console.log( "Called interfaceFunction A" )
}

defineExpose({ interfaceFunction })
</script>

<template>
  <div>
    ChildA
  </div>
</template>

Code snippet from ChildB.vue:

<script setup>

function interfaceFunction() {
  console.log( "Called interfaceFunction A" )
}

defineExpose({ interfaceFunction })
</script>

<template>
  <div>
    ChildB
  </div>
</template>

Answer №1

To update your slot's vnodes, simply add refs to them:

Please note: Consider switching from using h to cloneVNode, as the use of h is not officially documented yet: https://github.com/vuejs/docs/issues/2834

VUE SFC PLAYGROUND

<script setup>
import { useSlots, ref, h} from 'vue'

const slots = useSlots();
let $children;
const slotted = () => ($children = [], slots.default().map((vnode, i) => h(vnode, {ref: $children[i] ??= ref()})));

function callInterfaceFunction(){
  $children.forEach(({value: child}) => child.interfaceFunction());
}
</script>

<template>
  <button @click="callInterfaceFunction">Call from Container</button>
  <slotted/>
</template>

A more generalized approach involves recursively navigating nodes to gather refs (although this may not cover existing refs or slots, you can enhance it). This method allows for wrapping slotted components, like rendering them conditionally:

VUE SFC PLAYGROUND

<script setup>
import { useSlots, ref, h} from 'vue'

const slots = useSlots();
let $children;
const traverse = vnode => {
  vnode = h(vnode, {ref: $children[$children.length] ??= ref()});
  vnode.children = vnode.children?.map(traverse);
  return vnode;
};
const slotted = () => ($children = [], slots.default().map(traverse));

function callInterfaceFunction(){
  $children.forEach(({value:child}) => child.interfaceFunction?.());
}
</script>

<template>
  <button @click="callInterfaceFunction">Call from Container</button>
  <slotted/>
</template>
<script setup>
import { ref } from 'vue'

import Container from './Container.vue'
import ChildA from './ChildA.vue'
import ChildB from './ChildB.vue'

const childa = ref(null)

const swapped = ref(false);

function callInterfaceFunction() {
    childa.value?.interfaceFunction()
}
</script>

<template>
    <button @click="callInterfaceFunction">Call from App</button>

    <Container>
        <template v-if="!swapped"><ChildA ref="childa"/><ChildB/></template>
        <template v-else="swapped"><ChildB/><ChildA ref="childa"/></template>
    </Container>
    <button @click="swapped = !swapped">Swap</button>
</template>

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

Unable to use the same hexadecimal HTML entity in the value props of a React JSX component

Can someone explain why this code snippet displays dots as password and the other displays plain hexadecimal codes? <Field label="Password" value="&#x2022;&#x2022;&#x2022;&#x2022;&#x2022;" type="password" /> While this one disp ...

What is the best way to conceal a row when a particular field is devoid of content?

Is it possible to hide an entire table row if a field is empty? For example: If a certain field is empty, I want the entire row to be hidden, either using JavaScript or jQuery. I have tried some methods but none of them fully hide the row. Is there a way ...

Clicking anywhere outside a popup menu in JavaScript will deactivate a toggle and hide it

I have three different menu options: home,Clinic, and About. When I click on the Clinic option, a Megamenu appears, and if I click on it again, the Megamenu is hidden. I want the Megamenu to hide when clicking anywhere on the webpage. The issue is that cu ...

Using 'interface' declarations from TypeScript is unsupported in JS for React Native testing purposes

I have a ReactNative app and I'm attempting to create a test using Jest. The test requires classes from a native component (react-native-nfc-manager), and one of the needed classes is defined as follows export interface TagEvent { ndefMessage: N ...

Developing a Secondary User within Meteor.JS after Establishing the Primary User

Is it possible to automatically create a secondary user upon registration of the primary user using a form generated with the useraccounts:core package? An issue arises when attempting to run Accounts.createUser within Accounts.onCreateUser, resulting in ...

What is the best way to change an existing boolean value in Prisma using MongoDB?

Exploring prisma with mongoDb for the first time and faced a challenge. I need to update a boolean value in a collection but struggling to find the right query to switch it between true and false... :( const updateUser = await prisma.user.update({ where: ...

Nextjs is having trouble loading the Infogram script

Struggling to insert an Infogram into my project by pasting the script but it's not working as expected. All other scripts in _app.js are functioning properly, however, this particular script isn't loading the graphic even though it appears when ...

I am interested in obtaining the latitude and longitude of a specific city

I need to relocate the Google Map to a particular city based on user selection from a dropdown menu. I must obtain the latitude and longitude of the chosen city. Once the city is selected, I will determine its coordinates using the following code: var c ...

Tips for navigating through an array incrementally in a Controller using input provided by the user in the View

Greetings, I am currently working on a small website project using WAMPserver. The site is structured following an MVC design pattern. In one part of the process, I generate an array of strings in the controller. My goal is to display each element of this ...

What is the best way to integrate content from the tiptap text editor into a v-model?

Trying to directly bind this.newTutorial.content to editor.content, but no success so far. Console output: Code snippet: <style scoped> img.preview { width:200px; } .v-btn { height: 50px !important; min-width: 50px !important; } </sty ...

Why would one utilize window.location?.search?.split?

Could someone explain the purpose of using window.location?.search?.split('=')[1] and why the value of id is set to window.location?.search?.split('=')[1]? Code: function EndScreen() { const [score, setScore] = React.useContext(Score ...

The failure to parse an object in response to a JavaScript AJAX call

Why am I getting undefined in the console? Javascript code: var url = "/SitePages/AlertsHandler.aspx/GetAlert"; $.ajax({ type: "POST", url: url, data: '{alertId: \"' + alertId + '\"}', contentType: "applicati ...

Merging multiple observables with RxJs forkJoin

UPDATE : I'm currently facing a challenging issue that I can't seem to resolve. Within my code, there is a list of objects where I need to execute 3 requests sequentially for each object, but these requests can run in parallel for different obje ...

Transferring extra data from jQuery autocomplete to a PHP script

Hey there! I'm wondering if it's possible to pass extra parameters from jQuery autocomplete to a PHP page, which would then use them to query a database and return the results. While I know how to send the typed term from the input box, I'd ...

I am interested in using the v-for directive to iterate through a list of firebase image paths

As someone who is not a developer, please forgive me if my question seems simple. I appreciate your understanding. The code currently contains a v-for loop v-tab-item( v-for="(item, index) in getCharacterSkinList" :key="index" ) ...

What could be the reason for the data being retrieved but not showing up on the web page?

When fetching data from an API, I encounter a problem where the Loader displays but the data never shows up on the page. The inconsistency of this behavior is puzzling to me. This issue seems to be more prevalent on smartphones than on computers. useEffec ...

The issue of resolving NestJs ParseEnumPipe

I'm currently using the NestJs framework (which I absolutely adore) and I need to validate incoming data against an Enum in Typscript. Here's what I have: enum ProductAction { PURCHASE = 'PURCHASE', } @Patch('products/:uuid&apos ...

Retrieving outcomes from a sequence of callback functions in Node.Js

I've been struggling to get my exports function in Node.Js / Express app to return the desired value after going through a series of callback functions. I've spent hours trying to fix it with no success. Can someone provide some guidance? Here is ...

Express.js application experiencing technical difficulties

When attempting to create a simple Express application with the file called serv.js, I encountered an error. Here is the code snippet I used: var express = require('express'), app = express(); app.listen(3000, function() { c ...

Assistance is required for establishing a connection between php and js. The process begins with executing a sql query to extract the necessary data, which is then encoded into JSON format

I have encountered an issue with a project I am working on solo, involving a sidecart in a PHP file with external links to SQL, CSS, and JS. The problem arose when attempting to insert necessary data into JS using JSON encoding. <?php session_start(); ...