How do I get input from a v-menu? - vue.js

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>

Related

Vuetify v-menu leaves dropdown open after dialog appears

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>

Disable v-menu when no item

I've got a vuetify v-menu, with conditionnal item :
<v-menu min-width="225">
<template v-slot:activator="scope">
<v-btn small text color="primary" v-on="scope.on" :loading="actionLoading">
<v-icon>mdi-dots-vertical</v-icon>
</v-btn>
</template>
<v-list dense>
<v-list-item-group color="primary">
<v-list-item v-if="itemOneCondition()" #click="doSomething()">
<v-list-item-content>
<v-list-item-title>
Item 1
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item v-if="itemTwoCondition()" #click="something()">
<v-list-item-content>
<v-list-item-title>
Title 2
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-list-item-group>
</v-menu>
It happens that something every item is not visible (every v-if conditions are false). So the menu hasn't any item.
In this cas, the button is still activ, and a menu is opened with no entry :
Is there a way to disable the button when no item are visible ?
You need a v-if condition for the entire menu like so
<v-menu v-if="menuitems.length > 0" min-width="225"> </v-menu>
When there are no menu items, or the menu items array.length is 0, then the menu panel will not be displayed
Checkout this code snippet, You need to store the menu items in an array for this to work. In the code snippet below, when you replace
items: ["Item1","Item2",] with items: []
Notice that the menu with the black background will not be displayed
var app = new Vue({
el: "#menu",
data () {
return {
items: [
"Item1",
"Item2",
]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="menu" id="menu">
<ul style="background: black; color: yellow" v-if="items.length > 0">
<li v-for="(item, index) in items" :key="index">{{item}}</li>
</ul>
</div>
I used this solution, by adding a isAtLeastOneItemDisplayed() function :
<v-menu v-if="isAtLeastOneItemDisplayed()" min-width="225">
<template v-slot:activator="scope">
<v-btn small text color="primary" v-on="scope.on" :loading="actionLoading">
<v-icon>mdi-dots-vertical</v-icon>
</v-btn>
</template>
<v-list dense>
<v-list-item-group color="primary">
<v-list-item v-if="itemOneCondition()" #click="doSomething()">
<v-list-item-content>
<v-list-item-title>
Item 1
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item v-if="itemTwoCondition()" #click="something()">
<v-list-item-content>
<v-list-item-title>
Title 2
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-list-item-group>
</v-menu>
isAtLeastOneItemDisplayed : function(){
return this.itemOneCondition()
|| this.itemTwoCondition();
}

VueJs Vuetify Autocomplete with links

I'am using vuetify and i want make auto complete like the one on their official site.
But i'm faces some issues :
The items value not appear in the return list and i don't know how to make appear the links.
Here is my code.
Thanks You
<template>
<v-app>
<v-app-bar app color="primary" dark>
<v-app-bar-nav-icon #click="drawer = true"></v-app-bar-nav-icon>
<v-toolbar-title> Board </v-toolbar-title>
<v-spacer></v-spacer>
<v-autocomplete
:loading="loading"
:filter="v => v"
:items="items"
:search-input.sync="search"
v-model="select"
flat hide-no-data hide-details return-object placeholder="Search ...">
<v-list-tile
slot="prepend-item"
class="grey--text">
{{ items.length }} menus found
</v-list-tile>
<template slot="selection" slot-scope="{ item }">
{{item.name}} {{item.url}}
</template>
<template slot="item" slot-scope="{ item }">
<v-list-tile-content>
<p class='fullName'>{{item.name}} {{item.url}}</p>
</v-list-tile-content>
</template>
</v-autocomplete>
</v-app-bar>
<v-main>
<HelloWorld/>
</v-main>
</v-app>
I went through your issue and try to make a codepen and it worked.
My suggestion is that you should consider data structure when you use object with auto complete and it 's needed even you use v-select.
Please check this pen. https://codepen.io/endmaster0809/pen/qBZRywZ
items: [
{
name: 'Alerts',
url: 'https://vuetifyjs.com/en/components/alerts/'
},
{
name: 'Autocompletes',
url: 'https://vuetifyjs.com/en/components/autocompletes/#autocompletes'
}
],
select: {
name: 'Alerts',
url: 'https://vuetifyjs.com/en/components/alerts/'
},

How to "stop" an event?

I'm learning a Vuetifyjs and try writing a "file explorer".
There is an example:
codepen-snippet
I can’t understand how to make sure that when you click on the right icon, the entry in the "tree" does not become "active".
Probably need to “stop” the events, but I don’t know how to do it.
Tell me.
Thank.
I want to click on this menu: Menu
it became like this: need
not like now: now
Snippet:
<div id="app">
<v-app id="inspire">
<v-content>
<v-container >
<v-layout justify-center>
<v-card min-width=400>
<v-treeview
v-model="tree"
:open="open"
:items="items"
activatable
hoverable
item-key="name"
open-on-click
>
<template v-slot:prepend="{ item, open }">
<v-icon v-if="!item.file">
{{ open ? 'mdi-folder-open' : 'mdi-folder' }}
</v-icon>
<v-icon v-else>
{{ files[item.file] }}
</v-icon>
</template>
<template v-slot:label="{item}">
<v-hover v-slot:default="{ hover }">
<div class="d-flex align-center">
<span>{{item.name}}</span>
<v-menu
class="ml-auto"
style="display: inline"
:nudge-width="200"
offset-y
>
<template v-slot:activator="{ on }">
<!--
-->
<v-btn
v-show="hover"
icon
small
v-on="on"
class="pa-0 ma-0"
>
<v-icon small class="pa-0 ma-0">more_vert</v-icon>
</v-btn>
</template>
<v-card>
<v-list>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>mdi-information-variant</v-icon>
</v-list-item-action>
<v-list-item-title>Info</v-list-item-title>
</v-list-item>
<v-list-item v-if="item.type === 'process' || item.type === 'state'" #click="() => {}">
<v-list-item-action>
<v-icon>power_settings_new</v-icon>
</v-list-item-action>
<v-list-item-title>Status</v-list-item-title>
</v-list-item>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>create</v-icon>
</v-list-item-action>
<v-list-item-title>Rename</v-list-item-title>
</v-list-item>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>file_copy</v-icon>
</v-list-item-action>
<v-list-item-title>Copy</v-list-item-title>
</v-list-item>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>mdi-folder-plus</v-icon>
</v-list-item-action>
<v-list-item-title>Create folder</v-list-item-title>
</v-list-item>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>delete</v-icon>
</v-list-item-action>
<v-list-item-title>Delete</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-menu>
</div>
</v-hover>
</template
</v-treeview>
</v-card
</v-layout justify-center>
</v-container>
</v-content>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
open: ['public'],
files: {
html: 'mdi-language-html5',
js: 'mdi-nodejs',
json: 'mdi-json',
md: 'mdi-markdown',
pdf: 'mdi-file-pdf',
png: 'mdi-file-image',
txt: 'mdi-file-document-outline',
xls: 'mdi-file-excel',
},
tree: [],
items: [
{
name: '.git',
},
{
name: 'node_modules',
},
{
name: 'public',
children: [
{
name: 'static',
children: [{
name: 'logo.png',
file: 'png',
}],
},
{
name: 'favicon.ico',
file: 'png',
},
{
name: 'index.html',
file: 'html',
},
],
},
{
name: '.gitignore',
file: 'txt',
},
{
name: 'babel.config.js',
file: 'js',
},
{
name: 'package.json',
file: 'json',
},
{
name: 'README.md',
file: 'md',
},
{
name: 'vue.config.js',
file: 'js',
},
{
name: 'yarn.lock',
file: 'txt',
},
],
}),
})
What is happening here is that your click event is propagating to its parent element, so when you click on the icon to display the menu it also triggers the click event of your parent element which is the file or folder container.
You can add #click.stop to your v-btn in line 44, like this:
<template v-slot:activator="{ on }">
<!--
-->
<v-btn
v-show="hover"
icon
small
v-on="on"
class="pa-0 ma-0"
#click.stop
>
<v-icon small class="pa-0 ma-0">more_vert</v-icon>
</v-btn>
</template>
This will stop the event from propagating to its parent element, you can try it out here: codepen-snippet
Now when you click the button it will display your menu and won't change the active or inactive state on your files or folders.
To remove the blue highlighting of items when clicked, remove "activatable" from the v-treeview component:
<v-treeview
v-model="tree"
:open="open"
:items="items"
activatable
hoverable
item-key="name"
open-on-click >

Using v-tooltip inside v-menu activator in vuetify 2.0

How to use v-tooltip inside v-menu activator with vuetify 2.0? Previously it was working using slot="activator".
That's what I'm trying to combine:
<v-menu>
<template v-slot:activator="{on}">
<v-btn v-on="on">Menu Trigger</v-btn>
</template>
...list with menu options...
</v-menu>
and
<v-tooltip v-slot:activator="{on}">
<v-btn v-on="on">Menu Trigger with Tooltip</v-btn>
<span>Tooltip Content</span>
</v-tooltip>
Now I try to paste v-tooltip inside v-menu, what should happen with {on} here?
I think you're most likely unsure about the "conflicted" on objects passed to the template by multiple activator slots and how to apply all of the event handlers on the target element(s).
If that's the case, you can workaround this by assigning either one (or both) of them to a variable with a different name (see: assigning to new variable names), and then destructure and "restructure", which basically glues them back together (or merge them, technically speaking).
<v-menu>
<template #activator="{ on: onMenu }">
<v-btn v-on="onMenu">Menu Trigger</v-btn>
<v-tooltip bottom>
<template #activator="{ on: onTooltip }">
<v-btn v-on="{ ...onMenu, ...onTooltip }">Menu Trigger with Tooltip</v-btn>
</template>
<span>Tooltip Content</span>
</v-tooltip>
</template>
<!-- ...list with menu options... -->
</v-menu>
Or, use the slot props directly. Just make sure to name them properly so they won't introduce another naming conflict with the component's data and/or props.
<v-menu>
<template #activator="menu">
<v-btn v-on="menu.on">Menu Trigger</v-btn>
<v-tooltip bottom>
<template #activator="tooltip">
<v-btn v-on="{ ...menu.on, ...tooltip.on }">Menu Trigger with Tooltip</v-btn>
</template>
<span>Tooltip Content</span>
</v-tooltip>
</template>
<!-- ...list with menu options... -->
</v-menu>
Complete Demo:
new Vue({
el: '#app',
data: () => ({
items: [
{ title: 'Item #1' },
{ title: 'Item #2' },
{ title: 'Item #3' }
]
})
})
<link href="https://fonts.googleapis.com/css?family=Roboto:400|Material+Icons" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.x/dist/vuetify.js"></script>
<div id="app">
<v-menu>
<template #activator="{ on: onMenu }">
<v-btn v-on="onMenu">Menu Trigger</v-btn>
<v-tooltip bottom>
<template #activator="{ on: onTooltip }">
<v-btn v-on="{ ...onMenu, ...onTooltip }">Menu Trigger with Tooltip</v-btn>
</template>
<span>Tooltip Content</span>
</v-tooltip>
</template>
<v-list>
<v-list-tile
v-for="(item, index) in items" :key="index"
#click.prevent>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</div>