Search code examples
javascriptvue.jsvuetify.jsvuetifyjs3

Is it possible to use v-bind on the slot of an component in vue?


I want to create a mini profile in form of a menu by using Vuetify.js that can be called by different objects in my SPA so I thought it would be a good idea to create a component for it.

The component looks like this:

MiniProfileMenu.vue

<template>
    <v-menu
        v-model="menu"
        :close-on-content-click="false"
        location="end"
    >
        <template v-slot:activator="{ activator }">
            <slot v-bind="activator"/>
        </template>
        <v-card>
            <v-row>
                <v-col cols="auto" style="width: 64px">
                    Avatar
                </v-col>
                <v-col>
                    <h4>User</h4>
                    <p class="text-grey-darken-1">User Desc</p>
                </v-col>
            </v-row>
        </v-card>
    </v-menu>
</template>

<script>

export default {
    name: "MiniProfileMenu",

    data() {
        return {
            menu: false,
            activator: null,
        };
    },

    methods: {
        open(user, activator) {
            this.activator = activator;
            this.menu = true;
        },
        close() {
            this.menu = false;
        },
    },
}
</script>
<style scoped>
.profile-card {
    width: 100%;
}
</style>

And this is the case I would like to use it:

DashboardCommunityPage.vue

<template>
    <v-container>
        <v-row>
            <v-spacer />
            <v-col cols="auto">
                <mini-profile-menu ref="miniProfile">
                    <div
                        @click="openMiniProfile(user_uuid)"
                    >
                        Click me!
                    </div>
                </mini-profile-menu>
            </v-col>
            <v-spacer />
        </v-row>
    </v-container>
</template>

<script>
import MiniProfileMenu from "#/components/MiniProfileMenu.vue";

export default {
    name: "DashboardCommunityPage",

    components: {MiniProfileMenu},

    methods: {
        openMiniProfile(uuid) {
            this.$refs.miniProfile(uuid);
        }
    }
};
</script>

My problem is now, that I get the error Uncaught (in promise) TypeError: Cannot read properties of null (reading 'key') from the v-bind on the <slot /> in my MiniProfileMenu component. I would like to bind it to the div that is in the slot of the MiniProfileMenu so the menu appears next to it on click. Is it possible to do that in another way?

Thanks in advance


Solution

  • In the Vuetify menu component there is no props called activator.

    Instead you need to bind the props prop to where you want the menu to open on click.

    And in your menu component you can expose this props to the parent component by binding this to the slot.

    <!-- my-menu.vue -->
    <template>
        <v-menu>
            <template v-slot:activator="{ props }">
                <slot v-bind="props" />
            </template>
            <v-card>
                <!-- Content showed when opened -->
            </v-card>
        </v-menu>
    </template>
    
    <!-- parent component -->
    <template>
        <MyMenu v-slot="props"> <!-- We can access the props exposed from the child component -->
          <v-btn v-bind="props">
            Click me!
          </v-btn>
        </MyMenu>
    </template>
    

    vuetify menu usage

    Slot usage