Vuetify list subgroup auto collapse when clicked - vue.js

I have the following 2-level vuetify list . However, when I tried clicking on a child of the subgroup, the subgroup just collapsed like in the second half of this video.
I notice that when clicking on the child item, the sub list (Stock Statistics)'s isActive property is set to false.
How do I fix so that the subgroup remain open when I click on its child? Thanks in advance!
<template>
<v-list nav expand>
<template v-for="({ label, icon, group, subItems }, index) in items">
<v-list-group
v-if="subItems && subItems.length"
:key="index"
:group="group"
class="v-list--dense"
color="default"
append-icon="mdi-menu-down"
active-class="v-list-group--active"
>
<template #activator>
<v-list-item-icon class="mr-1">
<v-icon color="grey" v-text="icon"></v-icon>
</v-list-item-icon>
<v-list-item-content class="overflow-visible">
<v-list-item-title
class="subtitle-2"
v-text="$t(label)"
></v-list-item-title>
</v-list-item-content>
</template>
<template v-for="(child, idx) in subItems">
<v-tooltip v-if="!child.subChildItems" :key="idx" right>
<template #activator="{ on, attrs }">
<v-list-item
nuxt
:to="{ name: child.routeName }"
v-bind="attrs"
v-on="on"
>
<v-list-item-icon class="ml-4 mr-0">
<v-icon >mdi-circle-small</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title
v-text="$t(child.label)"
></v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
<span>{{ $t(child.label) }}</span>
</v-tooltip>
<v-list-group
v-else
:key="idx"
:group="child.subGroup"
sub-group
class="v-list--dense"
color="default"
prepend-icon="mdi-circle-small"
active-class="v-list-group--active"
>
<template #activator>
<v-list-item-content class="overflow-visible" style="margin-left: -16px;">
<v-list-item-title
class="subtitle-3"
v-text="$t(child.label)"
></v-list-item-title>
</v-list-item-content>
<v-list-item-icon class="ml-0 mr-0">
<v-icon>mdi-menu-down</v-icon>
</v-list-item-icon>
</template>
<template
v-for="(
{ label, routeName }, idxChild
) in child.subChildItems"
>
<v-tooltip :key="idxChild" right>
<template #activator="{ on, attrs }">
<v-list-item
nuxt
subheader
:to="{ name: routeName }"
v-bind="attrs"
v-on="on"
>
<v-list-item-icon class="ml-4 mr-0">
-
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title
v-text="$t(label)"
></v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
<span>{{ $t(label) }}</span>
</v-tooltip>
</template>
</v-list-group>
</template>
</v-list-group>
</template>
</v-list>
</template>

Related

Why doesn't the v-menu work with v-btn when the v-btn has v-for

I've been trying to implement a v-menu on a v-btn that as v-for. It works fine without v-for. I'm retrieving the category name using axios. So dont mind that. I just want the v-menu to work like that.
<div class="text-center">
<v-menu
:close-on-content-click="false"
:nudge-width="200"
offset-x
>
<template v-slot:activator="{ on, attrs }">
<v-btn
color="indigo"
dark
v-bind="attrs"
v-on="on"
:value="categoryid"
v-for="(categoryItem, i) in categoryList" :key="i"
#click="subcat(categoryItem._id)"
>
{{ categoryItem.cname }}
</v-btn>
</template>
<v-card>
<v-list>
<v-list-item>
<v-list-item-avatar>
<img
src="https://cdn.vuetifyjs.com/images/john.jpg"
alt="John"
/>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>John Leider</v-list-item-title>
<v-list-item-subtitle
>Founder of Vuetify</v-list-item-subtitle
>
</v-list-item-content>
<v-list-item-action>
<v-btn icon>
<v-icon>mdi-heart</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
<v-divider></v-divider>
</v-card>
</v-menu>
</div>

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();
}

Collapse all list and expand only the selected list in vuetify

I have a v-list-group with 2 sub-group inside it like in the image shown below. Whenever I click the parent list-group other groups are getting collapsed, but when I click a sub-group inside a list-group, other sub-group inside the list-group are not getting collapsed. Ex: when I click Admin, the Actions sub-group is not getting collapsed.
codepen: https://codepen.io/eajithkumar128/pen/BaoEeqW?editable=true&editors=101%3Dhttps%3A%2F%2Fvuetifyjs.com%2Fen%2Fcomponents%2Flists%2F
<div id="app">
<v-app id="inspire">
<v-card
class="mx-auto"
width="300"
>
<v-list>
<v-list-group
prepend-icon="account_circle"
value="false"
>
<template v-slot:activator>
<v-list-item-title>Users</v-list-item-title>
</template>
<v-list-group
no-action
sub-group
value="true"
>
<template v-slot:activator>
<v-list-item-content>
<v-list-item-title>Admin</v-list-item-title>
</v-list-item-content>
</template>
<v-list-item
v-for="(admin, i) in admins"
:key="i"
link
>
<v-list-item-title v-text="admin[0]"></v-list-item-title>
<v-list-item-icon>
<v-icon v-text="admin[1]"></v-icon>
</v-list-item-icon>
</v-list-item>
</v-list-group>
<v-list-group
sub-group
no-action
>
<template v-slot:activator>
<v-list-item-content>
<v-list-item-title>Actions</v-list-item-title>
</v-list-item-content>
</template>
<v-list-item
v-for="(crud, i) in cruds"
:key="i"
#click=""
>
<v-list-item-title v-text="crud[0]"></v-list-item-title>
<v-list-item-action>
<v-icon v-text="crud[1]"></v-icon>
</v-list-item-action>
</v-list-item>
</v-list-group>
</v-list-group>
<v-list-group
prepend-icon="account_circle"
value="false"
>
<template v-slot:activator>
<v-list-item-title>Users</v-list-item-title>
</template>
</v-list-group>
</v-list>
</v-card>
</v-app>
</div>
this can be simply done by using a v-model with every v-list-group. Something like this:
<v-list-group v-model="SubActive[header+subheader]" no-action sub-group v-for="(subheader, sIndex) in header.SubHeaderList" :key="sIndex" >
<template v-slot:activator>
<v-list-item-content v-on:click="subToggle(header,subheader)">
<v-list-item-title>
<span>{{subheader.Title}}</span>
</v-list-item-title>
</v-list-item-content>
</template>
SubActive is a Vue data object with keys as header+subheader (to uniquely identify each subheader) and its initial value will be set to false for all subheaders.
The subToggle function will simply switch the rest of the values to false(to collapse them all except the one which is clicked):
subToggle(brand, category) {
for (let i = 0; i < Object.keys(this.SubActive).length; i++) {
if (brand + category != Object.keys(this.SubActive)[i]) {
this.SubActive[Object.keys(this.SubActive)[i]] = false;
}
}
},

How to pass properties from grandchild menu object to grandparent?

my employer decided to expand the menu bar with another sub-pages, and things that works completely fine previously (simple one sub-menu) now don't want to work, because it has sub-menu, under another sub-menu.
Here is the pics:
As you can see when I hover "Acts" the sub menu with External and Internal documents works perfectly fine
but when I would like to move cursor on another sub-menu with "Director's Orders", whole menu is hiding. I think it's because second sub-menu (grandchild) don't pass info to main menu element (grandparent) to keep menu active, but I have no idea how to fix it.
Here is the code:
<v-menu open-on-hover bottom offset-x transition="slide-x-transition">
<template v-slot:activator="{ on }">
<v-list-item link v-on="on">
<v-list-item-content>
<v-list-item-title class="subtitle-1">Acts <v-icon class="menu-icon">keyboard_arrow_right</v-icon></v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
<v-list color="#F0FAFE">
<router-link to="/External"><v-list-item link>
<v-list-item-content>
<v-list-item-title class="subtitle-1 font-weight-medium">External</v-list-item-title>
</v-list-item-content>
</v-list-item></router-link>
<v-menu open-on-hover bottom offset-x transition="slide-x-transition">
<template v-slot:activator="{ on }">
<v-list-item link v-on="on">
<v-list-item-content>
<v-list-item-title class="subtitle-1 font-weight-medium">Internal <v-icon class="menu-icon">keyboard_arrow_right</v-icon></v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
<v-list color="#F0FAFE">
<v-menu open-on-hover bottom offset-x transition="slide-x-transition">
<template v-slot:activator="{ on }">
<v-list-item link v-on="on">
<v-list-item-content>
<v-list-item-title class="subtitle-1 font-weight-medium">Director's Orders <v-icon class="menu-icon">keyboard_arrow_right</v-icon></v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
<v-list
color="#F0FAFE"
v-for="(item, index) in Orders"
:key="index"
>
<router-link :to="'/' + item.title"><v-list-item link>
<v-list-item-content>
<v-list-item-title class="subtitle-1 font-weight-medium">{{ item.title }}</v-list-item-title>
</v-list-item-content>
</v-list-item></router-link>
</v-list>
</v-menu>
<router-link to="/Other"><v-list-item link>
<v-list-item-content>
<v-list-item-title class="subtitle-1 font-weight-medium">Other</v-list-item-title>
</v-list-item-content>
</v-list-item></router-link>
</v-list>
</v-menu>
</v-list>
</v-menu>
And little disclaimer. Yes I know this type of menu isn't a Material Design menu, which is the base for vuetify
I don't think v-menu supports nested menus (at least not when opening them with mouseover).
You'd have to make one yourself with nested v-hover. You can create a recursive component building the menu from a nested array of items.
Something like this:
<template>
<v-list color="#F0FAFE" class="menu">
<v-hover v-for="item in items" :key="item.title" v-slot="{ hover }">
<router-link v-if="item.route" :to="item.route" class="item">
<v-list-item link>
<v-list-item-content>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</router-link>
<v-list-item v-else class="item">
<v-list-item-content>
<v-list-item-title>{{ item.title }} -></v-list-item-title>
</v-list-item-content>
<NestedMenu v-if="item.children && hover" :items="item.children"/>
</v-list-item>
</v-hover>
</v-list>
</template>
<script>
export default {
name: "NestedMenu",
props: {
items: { type: Array, default: () => [] }
}
};
</script>
Here is a working example (which need some styling tho): https://codesandbox.io/s/nestedmenu-u8tk1?file=/src/components/NestedMenu.vue
Add more items and levels on menuItems in App.vue.

How to use v-slot:activator and v-on with child component?

I have some problems with my Vue.js Project.
Parent Component:
<v-menu>
<template v-slot:activator="{ on }">
<more-actions :ref="'moreActions' v-on="on" />
</template>
<v-list>
<v-list-item #click="handleClick()">
<v-list-item-title>
Sample
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
MoreActions Component
<template>
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<v-btn icon v-on="on" #click="$emit('click', $event)">
<v-icon small>
more_vert
</v-icon>
</v-btn>
</template>
<span>More Actions</span>
</v-tooltip>
</template>
This code is running well(under Vuetify v2.1.9), but doesn't run in Vuetify v2.1.15
(The menu is opend the top left corner.)
How can I fix this?
Here is running code in v2.1.15
<template>
<div class="text-center">
<v-menu>
<template v-slot:activator="{ on: menu }">
<v-tooltip bottom>
<template v-slot:activator="{ on: tooltip }">
<v-btn icon v-on="{ ...tooltip, ...menu }" #click="$emit('click', $event)">
<v-icon small>
more_vert
</v-icon>
<v-btn>
</template>
<span>Im A ToolTip</span>
</v-tooltip>
</template>
<v-list>
<v-list-item #click="handleClick()">
<v-list-item-title>
Sample
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
</template>
Please help me.
move this part to the parent component.
and using <slot /> instead of this part in Child Component.
<v-list>
<v-list-item #click="handleClick()">
<v-list-item-title>
Sample
</v-list-item-title>
</v-list-item>
</v-list>