Vuetify v-menu leaves dropdown open after dialog appears - vue.js

I have a v-menu which contains a v-list with a custom component.
<v-toolbar class="transparent">
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn v-bind="attrs" v-on="on">
<span><v-icon>mdi-menu</v-icon></span>
</v-btn>
</template>
<v-list>
<AdminAgentList/>
</v-list>
</v-menu>
... more ...
That component is a dialog which defines a v-list-item to slot into the v-list in the v-menu.
<template>
<div> <!-- Agent List -->
<v-dialog v-model="agentList_dlgOpen" persistent max-width="40%" #keydown.esc="agentList_dlgOpen = false">
<template v-slot:activator="{ on, attrs }">
<v-list-item v-bind="attrs" v-on="on">
<v-list-item-title><v-icon>mdi-account-multiple</v-icon> Agent List</v-list-item-title>
</v-list-item>
</template>
<v-card>
<v-card-title>Agent List Maintenance</v-card-title>
<v-card-text>
...
The problem I have is that when I click the dropdown menu item, the dialog appears and works fine. Once I dismiss the dialog, I'm back to the page but the menu item (the "Agent List" dropdown itself) is still showing hovering above the rest of the page. How do I get the dropdown list to disappear after I select something from it?

the problem is if the list item is the activator then it must be open until the dialog is open
my solution would be:
<v-menu offset-y v-model="menu">
<template v-slot:activator="{ on, attrs }">
<v-btn v-bind="attrs" v-on="on">
<span><v-icon>mdi-menu</v-icon></span>
</v-btn>
</template>
<v-list>
<AdminAgentList #close-menu="menu = false" />
</v-list>
</v-menu>
adding a v-model to the menu and controlling visibility
and in the other component AdminAgentList:
watch: {
agentList_dlgOpen(val) {
if (!val) {
this.$emit("close-menu");
}
},
},
a watcher to check if the dialog closed

Try this.
<v-toolbar class="transparent">
<v-menu #input="onMenuToggle" open-on-hover v-model="isOpened" offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn v-bind="attrs" v-on="on">
<span><v-icon>mdi-menu</v-icon></span>
</v-btn>
</template>
<v-list>
<AdminAgentList/>
</v-list>
</v-menu>
export default {
data() {
return {
isOpened: false,
selectedCategori: [],
categori: {},
overlay: false,
};
},
methods: {
onMenuToggle(val) {
this.isOpened = val;
},
},
};
</script>

Related

Open a dropdown with right click in Vue3 and Vuetify3

I am trying to work on the context menu for Vue3. I want to show the list of items under the v-menu by right-clicking on a dropdown button. I am working on this link as a reference but when I tried to do the same in my Vue3 file, It gives me an error like this-
Can anyone suggest what am I doing wrong? Here is the code-
<v-menu offset-y>
<template v-slot:activator="{ props }">
<v-btn
color="primary"
dark
v-bind="props"
#contextmenu.prevent="props.click"
>
Dropdown
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(item, index) in menuClick"
:key="index"
#click=""
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
I couldn't discover any context menu event in Vue3's doc and Vuetify's menu API. Although, I have an alternative in my mind that can do this job. You can utilize the .right modifier sync with v-model to open the menu with the right click of a button.
Here is the strategy-
Use v-model to control the v-menu toggling status.
On the right-click, set the v-model to true so the menu will be open.
On the left-click (default) set the v-model to false. (Do this step only if you don't want to open the menu on the default click.)
Here is a functioning demo-
const { createApp } = Vue
const { createVuetify } = Vuetify
const vuetify = createVuetify()
const app = createApp({
data: () => ({
menu: false,
items: [
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me 2' },
],
}),
}).use(vuetify).mount('#app')
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#3.1.2/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#3.1.2/dist/vuetify.min.css">
<div id="app">
<v-app>
<div class="d-flex justify-space-around mb-5 font-weight-bold">
I will open only with the right-click.
</div>
<div class="d-flex justify-space-around">
<v-menu v-model="menu">
<template v-slot:activator="{ props }">
<v-btn
color="primary"
v-bind="props"
#click.left.prevent="menu = false"
#click.right.prevent="menu = true"
>
Dropdown
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(item, index) in items"
:key="index"
:value="index"
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
</v-app>
</div>

Vuetify v-menu not expanding when component changes (Vue router)

I have a Vuetify v-menu on my App.vue, which appears on every page. When loading a page for the first time, it correctly expands (the menu is used for options such as Sign Out, Account Settings etc). When I navigate to another component (using Vue router), the v-menu does not expand when the new page is loaded. It doesn't work even if I click it (not just hover). What could be the cause of this?
...
<div v-if="signedIn" class="text-center hideOnMobile">
<v-menu
open-on-hover
bottom
offset-y
>
<template v-slot:activator="{ on, attrs }">
<v-btn
elevation='0'
color="primary"
dark
v-bind="attrs"
v-on="on"
class="userDropDown"
>
{{ username }}
<v-icon dark left>mdi-chevron-down</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(item, index) in items"
#click="selectSection(item.title)"
:key="index"
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
...
<router-view :uid='this.uid' :username='this.username' :userData='this.userData'></router-view>

How do I get input from a v-menu?

I am new to Vue, and I am trying to figure out it it all works together. I want to create a drop-down menu so the user can select what type of user they are.
This is my template:
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn color="blue" v-bind="attrs" v-on="on"> User Type </v-btn>
</template>
<v-list>
<v-list-item v-for="(item, index) in items" :key="index" v-model="user_type">
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
And this is my script:
data() {
return {
email: "",
password: "",
error: "",
first_name: "",
surname: "",
items: [{ title: "Client" }, { title: "Freelancer" }],
user_type: "",
};
}
Basically, I want the user to select whether they are a Client or a Freelancer, and I want to store that result in the user_type variable. I was able to store their other details using v-model's like so:
<div class="first_name">
<input
type="first_name"
v-model="first_name"
placeholder="First Name"
/>
</div>
I can't use a v-model with v-menu though, as it seems to return a boolean value for some reason. I have all of the basic functionality working, I just need to be able to access the user's choice in the drop-down menu. Is there something I am just not grasping here?
Thanks!
If you use v-list-item-group tag as parent of v-list-item you can use v-model on v-list-item-group and this will give the index of selected item.
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn color="blue" v-bind="attrs" v-on="on"> User Type </v-btn>
</template>
<v-list>
<v-list-item-group v-model="user_type">
<v-list-item v-for="(item, index) in items" :key="index">
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>

Vuetify: My navigation drawer is positioned over another element (toolbar)

I would like to put my navigation drawer under the toolbar.
I'm trying to achieve something like this :
I am trying to do something similar but all attempts are unsuccessful, at the moment I have the following:
My code:
<template>
<nav>
<v-snackbar v-model="snackbar" :timeout="4000" top color="success">
<span>Awesome! You added a new project.</span>
<v-btn text flat #click="snackbar = false">Close</v-btn>
</v-snackbar>
<v-toolbar app clipped-left >
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-app-bar-nav-icon #click.stop="drawer = !drawer"></v-app-bar-nav-icon>
<v-toolbar-title class="text-uppercase gr ey--text">
<span class="font-weight-light">estudos</span>
<span>vue</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn text
color="primary"
dark
v-bind="attrs"
v-on="on"
>
<v-icon left>expand_more</v-icon>
<span>Menu</span>
</v-btn>
</template>
<v-list>
<v-list-item v-for="link in links" :key="link.text" router :to="link.route">
<v-list-item-title>{{link.text}}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-btn text color="grey">
<span>Sign Out</span>
<v-icon right>exit_to_app</v-icon>
</v-btn>
</v-toolbar>
<v-navigation-drawer v-model="drawer" app class="indigo white--text">
<v-app-bar-nav-icon #click.stop="drawer = !drawer"></v-app-bar-nav-icon>
<v-layout column align-center>
<v-flex class="mt-5">
<v-avatar size="90">
<img src="/avatar-64.png">
</v-avatar>
<p class="white-text dubheading mt-1">
Estudos Vue
</p>
</v-flex>
<v-flex class="mt-4 mb-3">
<popup #projectAdded="snackbar=true" />
</v-flex>
</v-layout>
<v-list >
<v-divider></v-divider>
<v-list-item
v-for="link in links"
:key="link.text"
router :to="link.route"
>
<v-list-item-action >
<v-icon class="white--text">{{ link.icon }}</v-icon>
</v-list-item-action>
<v-list-item-content class="white--text">
<v-list-item-title>{{ link.text }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
<v-row>
<v-col
>
<v-img
max-height="76%"
max-width="100%"
src="/imgtest.jpg"
gradient="to top right, rgba(14,12,11,.51), rgba(14,12,11,.71)"
>
<v-img-title class="heading white--text">
Bien saude</v-img-title></v-img>
</v-col>
</v-row>
</nav>
</template>
<script>
import Popup from './Popup'
export default {
components: { Popup },
data() {
return {
drawer:false,
links:[
{icon: 'dashboard', text:'Dashboard', route:'/'},
{icon: 'folder', text:'My Projects', route:'/projects'},
{icon: 'person', text:'Team', route:'/team'},
],
items: [
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me 2' },
],
snackbar: true
}
},
}
</script>
I tried adding Block and removing the app, but it didn't solve the problem...
How do I put my drawer under the toolbar?
Add clipped to v-navigation-drawer props like:
<v-navigation-drawer
clipped>
<!-- ... -->
</v-navigation-drawer>
I would suggest following vuetify.js' default markup first.
Then you'll supposed to use clipped property in the <v-navigation-drawer> element like #mamadou-hady-barry already described. (<v-navigation-drawer clipped app>).
Secondly add the 'clipped-left' to the <v-app-bar> element resulting in: <v-app-bar clipped-left app>.
You are currently using <v-toolbar> which does not have a clipped-left property according to their "API".

Can a ui component be an activator for two items? (Trying to use a v-tooltip with a v-dialog)

I have a button that is the activator for a dialog in my template. But I also want to use a tooltiop with the button. (Said otherwise, when I hover over the button I'd like to see the v-tooltip and when I click the button I'd like to open the dialog.)
I've tried to use the "append" slot on the tooltip but no success. When I add the append slot, the button completely vanishes from the rendered page.
Is it even possible to use a v-tooltip with a v-dialog in veutify?
This is what I have that does not work.
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<v-app>
<v-dialog v-model="showAddPopup" persistent max-width="600px">
<v-tooltip slot="append" bottom>
<v-btn slot="activator" absolute fab dark left color="primary" #click="showPopup=true">
<v-icon dark>add</v-icon>
</v-btn>
<span>Tooltip</span>
</v-tooltip>
<app-add-new-evaluator-modal #closePopup="closePopup($event)" #submit="addNewEvaluator" />
</v-dialog>
</v-app>
The Vuetify docs explain how to do this, but you'll find it in the Menu Component:
https://vuetifyjs.com/en/components/menus#menu-with-activator-and-tooltip
Here's a simple example which opens a dialog with a button that has a tooltip:
<v-dialog>
<template #activator="{ on: dialog }">
<v-tooltip>
<template #activator="{ on: tooltip }">
<v-btn v-on="{ ...tooltip, ...dialog }">Button</v-btn>
</template>
<span>Tooltip text</span>
</v-tooltip>
</template>
<v-card>
Dialog content
</v-card>
</v-dialog>
Thanks #Traxo. All I had to do was add the slot="activator"to both components for it to work.
⚠️ ⚠️ problem with this solution, menu gets closed when you click anywhere on it ⚠️ ⚠️
Use this only if you can afford it to close anywhere you click:
<template>
<v-menu>
<template v-slot:activator="{ on: menu, attrs }">
<v-tooltip bottom>
<template v-slot:activator="{ on: tooltip }">
<v-btn v-bind="attrs" v-on="{ ...tooltip, ...menu }" fab>
<v-icon>mdi-account-multiple-plus</v-icon>
</v-btn>
</template>
<span>tooltip</span>
</v-tooltip>
</template>
<v-card>
<v-card-title class="headline grey lighten-2">
title
</v-card-title>
<v-card-text>
text
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text #click="dialog = false">
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-menu>
</template>