Leveraging v-for within a component that incorporates the <slot/> element to generate a versatile and interactive Tab menu

Currently, I am in the process of developing a dynamic tab menu using Vue 3 and slots. Successfully implementing tabs, I have created BaseTabsWrapper and BaseTab components. The challenge lies in using v-for with the BaseTab component inside a BaseTabsWrapper Component like so:

<section
    id="content"
    class="w-full mx-2 pr-2"
    v-if="incomingChatSessions && incomingChatSessions.length"
>
    <BaseTabsWrapper>
        <BaseTab
            v-for="chatSession in incomingChatSessions"
            :key="chatSession.id"
            :title="chatSession.endUser.name"
        >
            <p>{{ chatSession }}</p>
        </BaseTab>
    </BaseTabsWrapper>
</section>

An important note is that the incomingChatSessions object is asynchronous and sourced from a websocket. Tests confirm that this object works as intended and never returns empty.

In the BaseTabsWrapper template, key parts are:

<template>
    <div>
        <ul
            class="tag-menu flex space-x-2"
            :class="defaultTagMenu ? 'default' : 'historic'"
            role="tablist"
            aria-label="Tabs Menu"
            v-if="tabTitles && tabTitles.length"
        >
            <li
                @click.stop.prevent="selectedTitle = title"
                v-for="title in tabTitles"
                :key="title"
                :title="title"
                role="presentation"
                :class="{ selected: title === selectedTitle }"
            >
                <a href="#" role="tab">
                    {{ title }}
                </a>
            </li>
        </ul>
        <slot />
    </div>
</template>

The script includes:

<script>
import { ref, useSlots, provide } from 'vue'
export default {
    props: {
        defaultTagMenu: {
            type: Boolean,
            default: true,
        },
    },
    setup(props) {
        const slots = useSlots()
        const tabTitles = ref(
            slots.default()[0].children.map((tab) => tab.props.title)
        )
        const selectedTitle = ref(tabTitles.value[0])
        provide('selectedTitle', selectedTitle)
        provide('tabTitles', tabTitles)
        return {
            tabTitles,
            selectedTitle,
        }
    },
}
</script>

This represents the Tab component template:

<template>
    <div v-show="title === selectedTitle" class="mt-4">
        <slot />
    </div>
</template>

<script>
import { inject } from 'vue'
export default {
    props: {
        title: {
            type: String,
            default: 'Tab Title',
        },
    },
    setup() {
        const selectedTitle = inject('selectedTitle')
        return {
            selectedTitle,
        }
    },
}
</script>

A problematic segment in my script causing issues is:

const tabTitles = ref(
    slots.default()[0].children.map((tab) => tab.props.title)
)

Despite fetching multiple title elements via API, upon page load, the array tabTitles only contains one element. Interestingly, triggering a re-render results in the correct number of elements in tabTitles and the corresponding tabs on the menu display correctly. While confirming data flow from the websocket to hydrate the "incomingChatSessions" array functions accurately, the issue persists where tabTiles remains limited to one element.

Answer №1

Here is a possible solution:

computed(   
    () => slots.default()[0].children.map((tab) => tab.props.title) 
) 

This code snippet ensures that the computed property gets updated whenever there are changes in the component, such as slot modifications.

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

In Angular, you can easily modify and refresh an array item that is sourced from a JSON file by following these steps

Currently, I am working on implementing an edit functionality that will update the object by adding new data and deleting the old data upon updating. Specifically, I am focusing on editing and updating only the comments$. Although I am able to retrieve th ...

Is it possible to dynamically add and remove items using React state?

I am currently working on implementing a dynamic queue of game players in my React state. The goal is to avoid hardcoding the number of players who can participate and achieve this state update using a JS FIFO queue. My objective is to create a player que ...

jQuery's Offset().left is experiencing some issues and not functioning correctly

Do you have a question about the jQuery offset() function? On my website, I utilize it to show an "email a friend" window when the email icon is clicked. However, the problem is that the window ends up stuck to the right side of the browser's window ...

Progress Indicator on my online platform

I've been attempting to remove a loading bar from my website, but I can't seem to locate it in the site files. I even tried using Google Chrome's inspection tool, but I couldn't pinpoint the loader. Can someone please assist me? Visit ...

Ways to display a price near a whole number without using decimal points

Currently, I am working on an ecommerce project where the regular price of an item is $549. With a discount of 12.96% applied, the sale price comes down to $477.8496. However, I want the sale price to be displayed as either $477 or $478 for simplicity. Yo ...

Adjust the divs right element by adding or removing 1 pixel for every size change in the browser

I have been exploring different approaches to achieve this task and it seems like using javascript might be the most effective way. I am currently dealing with a stubborn social icon container placement issue. More details on my previous question can be fo ...

How can I retrieve elements i from each array in HandlebarsJS and then access element j, and so on?

Given a JSON like this: { "network": [ { "name": [ "John", "Jill", "June" ] }, { "town": [ "London", "Paris", "Tokyo" ] }, { "age" : [ "35", "24", "14" ] } ] } Unfortunately, my data is in this format and I have to work w ...

Tips on aligning a v-btn alongside v-expansion-panels on the same row

Struggling with aligning my layout. Trying to get a single set of v-expansion-panels and a v-btn in the same row, both visually centered within a card. I managed to almost achieve it in this codepen: https://codepen.io/anzuj/pen/PoPPbdw with the following ...

Having trouble with installing Vue CLI?

I am encountering issues while attempting to set up VueJS. I am currently utilizing Bash on Ubuntu on Windows node -v v15.12.0 npm -v 7.6.3 Initially, I attempted the following: npm install -g @vue/cli However, this resulted in various warnings and ...

Trouble accessing environment variables within a React application, specifically when using webpack's DefinePlugin in a Dockerfile

I can't figure out why console.log is printing undefined. The files Makefile, config.env, webpack.config.js, and package.json are all located in the root of my project. Makefile: docker-run: docker docker run -it --env-file config.env -p "80:80" ...

Exploring the power of Angular's ng-repeat to generate hierarchical lists

I am looking to display a structured list of layers and sublayers by looping through an object using ng-repeat. var lyrslist = [ { layername: "Base Maps", layertype: "layer" }, { layername: "Open Street Map", layertype: "sublayer" },    { layer ...

Truncating decimal points in JavaScript

In this scenario, if the number after the decimal point is 0, then the zero should be removed. Otherwise, the number should be displayed as it is. Here are some examples of what I am aiming for in vue: 100.023 => 100.023 1230.0 => 1230 ...

Is it possible to pass slot data back to the parent component in Vue in order to propagate a prop down?

Within my parent component, I am using a MyGrid component to display data. Inside MyGrid, I have logic that checks the type of each item and applies a class called typeSquare if it meets certain criteria. To maintain the simplicity and "dumbness" of MyGr ...

Converting counterup2 to pure vanilla JavaScript: step-by-step guide

Is there a way to convert the counterUp2 jQuery code to vanilla JavaScript? const counters = document.querySelectorAll('.counter'); function count(element) { let currentValue = 0; const targetValue = parseInt(element.innerText); let interv ...

Passing parameters as an array in Angular can be done by using the format: ?category[]=1&category[]=2&category[]=3,

Struggling to send an array using the $http.get() method in AngularJS. Here's my current approach: $http.get('/events.json', {params: {category_id: [1,2]}}); While I anticipate the request to be sent as /events.json?category_id[]=1&cat ...

Implementing JavaScript: Grouping JSON Response by Date and Category in a Table

The API response provided below contains sample data. {"success":true,"transaction":[{"_id":"58efd5717ddda769f26793fc","transId":"Exp/04-17/17","trpId":"Trav/dfsd/04-17/12","tripId":"58efd4dc7ddda769f26793f8","userId":"58ac19eaec1e7e4628be6f01","expenseHe ...

"Encountering a glitch involving Vue.js 3, Pinia, and a centralized store

While using Pinia in a Vue.js 3 project, I encountered an issue. The problem arises when I attempt to load constant JSON structures from my backend using the file src/store/constants.store.ts // @ts-check import { defineStore } from "pinia" impor ...

Press a button to activate a function on a dynamically created table using Ajax

On my website, I have an ajax function that dynamically generates a table and displays it inside a designated div. Below is the PHP code called by the Ajax function. echo "<table border='1' cellspacing='12' cellpadding='4' ...

How come the Jquery :odd selector picks out the even elements?

<html> <head> <script type="text/javascript" src="jquery-1.7.1.js" ></script> <script type="text/javascript"> $(function() { $("p:odd").html('modified'); }); </script> </head> & ...

How to dynamically add a form to your website

Looking to dynamically insert a form on a page based on the value selected from a datalist, all without having to reload the entire page. <form action='#' method='get'> <input list="category" name="category"> <da ...