Reimagining the activator slot in the Vuetify V-Menu component

I'm attempting to develop a custom component based on vuetify's v-menu component.

This menu should be invoked from vuetify's dialog in two scenarios:

  1. By clicking the "Add row" button located at the top of the dialog content
  2. By clicking on the "Edit" icon button on each row of the v-data-table component

The key point is that the same menu should appear in both cases. The difference lies in the calling component - for the first case, it should be a v-btn with specific text, and for the second case, a v-icon with a specific icon.

Based on the vue and vuetify documentation, I believe I need to redefine v-slot:activator, but I'm encountering difficulties where the component always defaults to a specific value for v-slot:activator.

Using Vue 2.6.11 and Vuetify 2.2.3.

Below is the code snippet:

Dialog.vue:

<template>
  <v-dialog v-model="dialog" max-width="500px" persistent>
    <v-card>
      <v-card-title>
        <v-spacer></v-spacer>
        <menu-component/>
      </v-card-title>
      <v-card-text>
        <v-data-table
          :headers="tableHeaders"
          :items="tableContent"
        >
          <template v-slot:item="props">
            <tr>
              <td>{{ props.item.id }}</td>
              <td>{{ props.item.text }}</td>
              <td class="text-center">
                <menu-component>
                  <template v-slot:activator="{ on }">
                    <v-icon v-on="on">mdi-pencil</v-icon>
                  </template>
                </menu-component>
              </td>
            </tr>
          </template>
        </v-data-table>
      </v-card-text>
      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn @click="close">{{ "Close dialog" }}</v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

<script>
  import MenuComponent from "./MenuComponent";

  export default {
    components: {
      'menu-component': MenuComponent
    },
    data() {
      return {
        tableContent: [
          { id: 1, text: 'some text'}
        ],
        tableHeaders: [
          {text: 'ID'},
          {text: 'Text'},
          {text: 'Actions', align: 'center'}
        ]
      }
    },
    props: {
      dialog: Boolean
    },
    methods: {
      close() {
        this.$emit('close-dialog');
      }
    }
  }
</script>

MenuComponent.vue:

<template>
  <v-menu bottom left
          v-model="menu"
          :close-on-content-click="false">
    <template v-slot:activator="{ on }">
      <v-btn v-on="on">Add row</v-btn>
    </template>
    <v-card width="300">
      <v-container>
        <v-layout wrap>
          <v-text-field label="Text"/>
        </v-layout>
      </v-container>
      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn @click="menu=false">{{ "Close" }}</v-btn>
      </v-card-actions>
    </v-card>
  </v-menu>
</template>

<script>
  export default {
    data() {
      return {
        menu: false,
      }
    }
  }
</script>

Intended Design:

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

Current Output:

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

Answer №1

A great way to achieve what you want is by passing your slots to a child component that is wrapped. Someone created a helpful gist that explains how to do this: https://gist.github.com/loilo/73c55ed04917ecf5d682ec70a2a1b8e2#gistcomment-3121626

Here is the code you should include in your MenuComponent.vue:

<template>
  <v-menu bottom left
    v-model="menu"
    :close-on-content-click="false"
  >

    <!-- pass through scoped slots -->
    <template v-for="(_, scopedSlotName) in $scopedSlots" v-slot:[scopedSlotName]="slotData">
      <slot :name="scopedSlotName" v-bind="slotData" />
    </template>

    <!-- pass through normal slots -->
    <template v-for="(_, slotName) in $slots" v-slot:[slotName]>
      <slot :name="slotName" />
    </template>


    <v-card width="300">
      <v-container>
        <v-layout wrap>
          <v-text-field label="Text"/>
        </v-layout>
      </v-container>
      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn @click="menu=false">{{ "Close" }}</v-btn>
      </v-card-actions>
    </v-card>
  </v-menu>
</template>

By implementing this code, all the slots will be transferred from the parent component to the child component.

This method will be effective for all slots of a component. However, if you want to customize it for your specific scenario, you can use the following code:

<template>
  <v-menu bottom left
    v-model="menu"
    :close-on-content-click="false"
  >

    <!-- pass through scoped slots -->
    <template v-slot:activator="slotData">
      <slot v-if="$scopedSlots.activator" name="activator" v-bind="slotData" />
      <v-btn v-else v-on="slotData.on">Add row</v-btn>
    </template>


    <v-card width="300">
      <v-container>
        <v-layout wrap>
          <v-text-field label="Text"/>
        </v-layout>
      </v-container>
      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn @click="menu=false">{{ "Close" }}</v-btn>
      </v-card-actions>
    </v-card>
  </v-menu>
</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

Using HTML and JavaScript to automatically update one input date based on changes made to another

Currently, I am developing an Angular application and encountered a challenge with two date input fields: <div class="col-lg-3"> <div> {{ dataInizioLabel }} </div> <input required type="datetime-local" ...

Is it possible to associate non-HTML elements such as v-btn with Nuxt's tag prop?

Here is the code I have been working on in my editor: <nuxt-link :to="www.test.com" tag="v-btn" /> Link Button </nuxt-link> I realized that v-btn is not a standard HTML tag, but rather a specific one for Vuetify. When I write the code this wa ...

Executing a custom object function in AngularJS by using the ng-click directive

As I navigate my way through AngularJS, I find myself grappling with the concept of calling a custom method of an object and wonder if there's a simpler approach: https://jsfiddle.net/f4ew9csr/3/ <div ng-app="myApp" ng-controller="myCtrl as myCtr ...

What is the best way to retrieve a value from an asynchronous function in Node.js?

var fs = require('fs'); var ytdl = require('ytdl-core'); var favicon = require('serve-favicon'); var express = require('express'); var app = express(); app.use(favicon(__dirname + '/public/favicon.png')); ...

New post: The vue component that was released lacks CSS (NPM)

For the first time, I am releasing a Vue component on NPM and everything seems to be in order, except for one issue - the CSS is missing. While it functions perfectly when tested locally, after installing the npm package in a test project and importing the ...

Are your GetJSON requests failing to execute properly?

I have a code snippet that executes in a certain sequence and performs as expected. <script> $.getJSON(url1, function (data1) { $.getJSON(url2, function (data2) { $.getJSON(url3, function (data3) { //manipulate data1, data2, ...

Confirm that a new class has been assigned to an element

I'm having trouble creating a unit test for a Vue.js component where I need to check if a specific CSS class is added to the template. Below is the template code: <template> <div id="item-list" class="item-list"> <table id="item ...

Implementing a dynamic background change based on the current date in JavaScript

Is it possible to change the background of the body element based on the season using JavaScript? Here is a code snippet that demonstrates how to achieve this: // Function to determine the current season in the southern hemisphere // If no date is prov ...

Cannot load JavaScript in Ajax tabs

I have implemented this ajax tabs on my website. However, the JavaScript code inside the content.htm file seems to be malfunctioning. Below is the code snippet I am using: Javascript $(document).ready(function(){ $("button").click(function(){ ...

Exploring the Crossroads of JSP and External Javascript Documents

I am new to using external JavaScript files (*.js). I have my JSP file ready, but my manager wants me to incorporate graphics into it. After searching, I found some *.js files. However, I am unsure of how to connect them with my JSP page. I need a way to ...

Sequential cascade filtering without a preset default option

Please note: The following code snippet has been adjusted and is now functional. In a MySQL database table, I have the following columns with corresponding values: Category (Fruit, Vegetable) Type (Apple, Orange, Pumpkin, Potato) Subtype (Red Delicious, ...

Attempting to set up an Ajax webform with various outputs, but encountering issues with functionality

I'm encountering an issue while creating interactive exercises. I want to display correct or incorrect answers immediately after submission using JSON for retrieving responses, as suggested in a forum. However, my AJAX code isn't working at all. ...

Click a button to load a different view in CodeIgniter

How can I show another view of Controller using Ajax/Javascript when clicking a button? I attempted something, but it's not working as expected. Javascript: <script> $(document).ready(function(){ $("#details").click(function(){ $( ...

Need some assistance in finding a way to input multiple values from multiple buttons into a single input field in JavaScript

Hello, I am looking for a little help with reading multiple values using multiple buttons such as 1, 2, and 3, and displaying the output in the input like '123' instead of just one number at a time. Concatenate numbers with every click. <inpu ...

Challenges with communication between Ajax and Axis2

I've been struggling to obtain results from this specific Ajax command, but unfortunately, I have not been successful. $.ajax({ type: "get", url: "http://[localhost]:80**/*****/getdata.jws", data: 'method=s**& ...

Having trouble invoking html2canvas within an AngularJS app

When I define html2canvas functions in my controller, the alert in html2canvas doesn't get fired and my canvasToImageSuccess function is not executed. Am I missing something here? In my controller, I have defined html2canvas functions as shown below ...

Is it possible for the 'error' attribute to be deemed invalid or inappropriate within ajax?

I am encountering an issue with my mobile cordova application. When attempting to log in, I am facing the following error: Error: JavaScript runtime error - Object doesn't support property or method 'error' The error is being traced back t ...

Different from Window.Print()

I am looking to implement a print button that will trigger the printing of the entire webpage when clicked. I have been attempting to achieve this using Window.print() in JavaScript, but I encountered an issue where the link stops working if the print bu ...

Saving the initial state value in a variable in Vue.js is a crucial step in managing and

My dilemma involves an object in the Vuex store containing data that I need to utilize within a component. I have successfully accessed the data using a getter in the component. However, I am facing a challenge in preserving the initial value of this objec ...

Struggling to find the right strategy for obtaining real-time data while implementing customized filters

After spending a week scratching my head and experimenting with different approaches, I'm hoping to find some help here... I am working on an application that needs to provide real-time data to the client. I initially considered using Server-Sent-Eve ...