Elevate the element from the choice API to the organization API using this.$parent

I recently developed a Vue 3 component called "Tab" using the option API. Here is the code:

export default {
    name: "Tab",
    props: {
        name: {required: true},
        iconClass: {required: true},
        selected: {default: false}
    },
    data() {
        return {
            isActive: false
        }
    },
    mounted() {
        this.isActive = this.selected;
    },
    created() {
        this.$parent.tabs.push(this);
    },
}

However, I now want to convert it using the composition API. This is the updated code:

import {onBeforeMount, onMounted, ref} from "vue";

export default {
    name: "Tab",
    props: {
        name: {required: true},
        iconClass: {required: true},
        selected: {default: false}
    },
    setup(props, {parent}) {
        const isActive = ref(false)

        onBeforeMount(() => {
            parent.tabs.push(this);
        })

        onMounted(() => {
            isActive.value = props.selected;
        })

        return {isActive}
    }
}

A warning message is showing in the console:

Unhandled error during execution of beforeMount hook

This seems to be related to this specific line of code:

 parent.tabs.push(this);

Any suggestions or ideas for debugging?

*** UPDATE ***

The tabs component (parent) has the following setup:

name: "Tabs",
    setup() {
        const tabs = ref([])

        const selectedTab = (selectedTab) => {
            tabs.value.forEach(tab => {
                tab.isActive = (tab.name === selectedTab.name);
            })
        }

        return {tabs, selectedTab}
    }

*** UPDATE 2 ***

Even after trying with provide/inject, the tabs do appear but do not change content when selecting another tab.

Here are the implementations for the "Tabs" component (parent):

<template>
    <div>
        <div class="nav-wrapper">
            <ul class="nav nav-pills nav-fill flex-column flex-md-row">
                <li class="nav-item" v-for="tab in tabs" :key="tab">
                    <a class="nav-link mb-sm-3 mb-md-0" @click="selectedTab(tab)" :class="{'active' : tab.isActive}" href="javascript:void(0)">
                        <i class="ni mr-2" :class="[tab.iconClass]"></i>{{ tab.name }}
                    </a>
                </li>
            </ul>
        </div>
        <div class="tab-content">
            <slot></slot>
        </div>
    </div>
</template>

<script>
import {provide, ref} from "vue";

export default {
    name: "Tabs",
    setup() {
        const tabs = ref([])

        const selectedTab = (selectedTab) => {
            tabs.value.forEach(tab => {
                tab.isActive = (tab.name === selectedTab.name);
            })
        }

        provide('tabs', tabs.value)

        return {tabs, selectedTab}
    }    
}
</script>

And here's the "Tab" component code:

<template>
    <div class="tab-pane fade show" :class="{'active' : isActive}">
        <slot></slot>
    </div>
</template>

<script>
import {onBeforeMount, inject, onMounted, ref} from "vue";

export default {
    name: "Tab",
    props: {
        name: {required: true},
        iconClass: {required: true},
        selected: {default: false}
    },
    setup(props) {
        const isActive = ref(false)

        onBeforeMount(() => {
            const tabs = inject("tabs")
            tabs.push({
                name: props.name,
                iconClass: props.iconClass,
                selected: props.selected,
            })
        })

        onMounted(() => {
            isActive.value = props.selected;
        })

        return {isActive}
    }    
}
</script>

Answer №1

If you need to retrieve the parent from the instance, you can utilize the getCurrentInstance() method

To access the data, attempting instance.parent.data won't work as the data is not defined there. Vue provides access to the data passed to the view through instance.parent.proxy, allowing you to reach the Proxia via instance.parent.proxy.tabs

While theoretically feasible, it is strongly advised against accessing parent data in this manner. It might be more appropriate to pass props directly (in a parent-child relationship), or use the provide/inject pattern, or even consider utilizing a global store if the parent is only used once. Relying on parent.proxy.* relies on internals that could potentially change in the future.

An example demonstrating passing with provide/inject:

var app = Vue.createApp({
  setup() {

    const tabs = Vue.ref([1])
    Vue.provide('tabs', tabs)

    const selectedTab = (selectedTab) => {
      tabs.value.forEach(tab => {
        tab.isActive = (tab.name === selectedTab.name);
      })
    }

    return {
      tabs,
      selectedTab
    }
  }
});

app.component("child-component", {
  template: `<div >🧒<button @click="gift">🎁</button></div>`,
  setup() {
    const instance = Vue.getCurrentInstance();
    const tabs = Vue.inject('tabs')
    const gift = ()=>{
      instance.parent.proxy.tabs.push('🌼'); // using proxy
      tabs.value.push('🌻'); // using inject
    }
    Vue.onBeforeMount(() => {
      gift();
    })

    return {gift}
  }
});

app.mount("#app");
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7006051530435e405e46">[email protected]</a>/dist/vue.global.prod.js"></script>
<div id="app">
👩‍🦰
  {{tabs}}
  <child-component></child-component>
  <child-component></child-component>
</div>

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

React - Incorrect components experiencing style changes due to setTimeout

Check out the code snippet here: https://jsfiddle.net/69z2wepo/204131/ A main component displays two 'notifications' each with different disappearance timings. class Page extends React.Component { constructor(props) { super(props); t ...

Implementing a peculiar timing mechanism with the integration of socket.io, jQuery Mobile, and the socket.emit() function

Currently in the process of working with cordova and node.js socket.io, I encountered a peculiar issue with socket.emit(); The following code fails to enter 'room', despite having correct coding: client-side jsfile.js //Two global variables fo ...

Unable to set up service worker with Workbox window

I need help migrating from v3 to v4 in my Vue.js app. I am using workbox-window (CDN) and workbox-webpack-plugin for this task. While everything works fine locally with an http-server, I encounter an error after deployment that prevents the service worker ...

Display the div element only when it is positioned in the center of the page

I am looking to create a smooth fade-in effect for a div when the user scrolls away from the top of the page, but I want the div to be hidden again as they approach the bottom of the page. Specifically, I would like the div to remain hidden when it is wit ...

Enabling Event bus suggestions for Typescript: A step-by-step guide

Hello, I've encountered an issue while attempting to add types for the TinyEmitter library. Specifically, I need to define two methods. First: addEventListener(e: string, (...args: any[]) => void): void; Second: emit(e: string, ...args: any[]): vo ...

Click event doesn't trigger the 'else if' statement in jQuery

Having trouble with a button click issue. In the following code, when the button is clicked, it checks if the text on the button is "day". If so, it changes the background-color of the body to red and updates the button text to "night". I am struggling wit ...

Compiling modal window content in AngularJS can lead to the creation of controllers that are left disconnected

I implemented a modal window triggered by fancybox in my project. Once the modal is displayed, fancybox triggers a "modalShown" event that is listened for by AppController. In this listener, $compile is called on the modal content to create the ModalContro ...

Is there a way to use regex to selectively color JSON keys?

My goal in JavaScript is to extract all of the JSON keys using regular expressions. I am assuming that the JSON data will be formatted with each key-value pair on a new line, like this: { "name": "Jane", "age": 30, } In simple terms, I am looking ...

Issue with displaying selected value and options in Mat-select when using formarray - Reactive forms in Angular

I've been working on the code below to create dropdowns, but I'm having trouble getting the selected value and options to show up in the dropdowns. Can you help me figure out what's wrong with the code? Component code testForm: FormGroup; ...

Using Google Apps Script to input data into the next available row

Utilizing Google Apps Script, I am retrieving data from another spreadsheet and storing it daily in a sheet named "DATABASE". Although my current solution is basic, it keeps overwriting existing data. I wish to enhance the script to copy data from the imp ...

If I click on a different VueJS menu, make sure to close the current menu

When using a component menu, each item is displayed independently. However, I would like the open items to close automatically when I click on another item with the menu. I employ a toggle functionality on click to control the opening and closing of the c ...

Can one retrieve an express session using the sessionID given?

I have a NodeJS Express application with express-session that works well, however, it needs to be compatible with a cookie-less PhoneGap app. My question is: Can I access the data in an express session using the sessionID? I was thinking of adding the se ...

Can a website be saved entirely, including the initial HTML page, and accessed without an internet connection?

Our unique website utilizes AJAX technology to communicate with the server without making additional page requests after the initial setup. This allows users to seamlessly switch between online and offline modes during a session, automatically synchronizin ...

Numerous Customized Google Maps

On my contact page , I have a Google Map V3 that is styled and mostly functional, except for some sprite image display issues. Now, I need to include the same JSON data in two separate maps on my showrooms page . How can I style multiple maps with differen ...

Angular ngFor Directive Failing to Display Menu Item Information on Right-Click Context Menu

Currently encountering an issue with implementing a right-click function in my context menu. The menu items are not appearing due to the second ngFor="let row" condition... however, I require the selected row object from a right click to pass in a JSON val ...

Material UI Table dynamically updates with Firestore real-time data

My current code aims to update a Material UI table in real-time with data from a Firestore database. I can fetch the data and store it in an array, but when I assign this array to the table data, nothing changes. I've heard that I should use states fo ...

Integrating Firebase into Vue.js 2 application using Vue CLI with webpack configuration

Recently, I started using vue-cli with a webpack template and I'm looking to integrate Firebase as my database for the Vue app. Here's how I imported Firebase into my app: Main.js //imported rest all required packages just dint mention here imp ...

Incorporate the module into both the parent and child class

In my coding project, I have a situation where both a parent class and a child class are importing the same lodash library. This raises the question: will the final bundled JavaScript file contain duplicate lodash code? //Parent Class import Component fro ...

I am attempting to implement an Express static middleware as demonstrated in this book, but I am having trouble understanding the intended purpose of the example

I'm currently studying a chapter in this book that talks about Express, specifically concerning the use of express.static to serve files. However, I'm encountering an issue where the code catches an error when no file is found. I've created ...

Modifying the data of an HTML form using Javascript, encrypting the information, and transferring it to PHP

I am new to PHP and have a simple code management question. I would like to create an input box in HTML where someone can enter their name, and with the use of Javascript, generate a link with an encoded version of the name preceded by a website string. Wh ...