vuetify v-list with reactive source collapses upon adding or removing items - vue.js

not sure if the reactivity part is relevant, but I use vuetify with Meteor.js and my problem is that whenever the number of items in the sub-group changes, it collapses the entire list. That is extremely annoying as the list has two levels and I need to reopen both levels to get back to the group I am editing.
I use exactly the same structure as the official sub-group example:
https://vuetifyjs.com/en/components/lists/#sub-group
Say the number of items in the Admin section in that example above changes (which means reassigning a different array to a local variable in data(){}). Then the whole list will collapse.
Is there anything I can do to keep having opened the current item?
Thanks for any tips!

I tested [https://vuetifyjs.com/en/components/lists/#sub-group][1] in Vue 2 and for me, the menu didn't close when a new item was added.
I pushed a new item into data.admin
I assigned a totally new array to data.admin
In both cases, the menu remained open.
I think the question is, are you updating a component state or props.
Because updating component props would probably cause it to rerender and therefore close the menu.
Here is the code that worked for me:
<template>
<v-app>
<v-main>
<v-card class="mx-auto" width="300">
<v-list>
<v-list-group :value="true" prepend-icon="mdi-account-circle">
<template v-slot:activator>
<v-list-item-title>Users</v-list-item-title>
</template>
<v-list-group :value="true" no-action sub-group>
<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="([title, icon], i) in admins" :key="i" link>
<v-list-item-title v-text="title"></v-list-item-title>
<v-list-item-icon>
<v-icon v-text="icon"></v-icon>
</v-list-item-icon>
</v-list-item>
</v-list-group>
<v-list-group no-action sub-group>
<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="([title, icon], i) in cruds" :key="i" link>
<v-list-item-title v-text="title"></v-list-item-title>
<v-list-item-icon>
<v-icon v-text="icon"></v-icon>
</v-list-item-icon>
</v-list-item>
</v-list-group>
</v-list-group>
</v-list>
</v-card>
<v-btn #click="addElement">Add element</v-btn>
</v-main>
</v-app>
</template>
<script>
export default {
name: 'App',
data: () => ({
admins: [
['Management', 'mdi-account-multiple-outline'],
['Settings', 'mdi-cog-outline'],
],
cruds: [
['Create', 'mdi-plus-outline'],
['Read', 'mdi-file-outline'],
['Update', 'mdi-update'],
['Delete', 'mdi-delete'],
],
}),
methods: {
addElement() {
this.admins.push(['New', 'mdi-account-multiple-outline']);
// Completely change the menu
/* this.admins = [
['New', 'mdi-account-multiple-outline'],
['Management', 'mdi-account-multiple-outline'],
['Settings', 'mdi-cog-outline'],
]; */
},
},
};
</script>

Related

Retain title and icon on navigation drawer

I'm currently using Vue and vuetify to build a navigation drawer container. I have just about what I am looking for... However, when I click on the drawer icon, I lose the Title and the drawer icon. I want those to both stay there even when the drawer is open.
Is there any way to achieve this by using simply vuetify? I can obviously add a custom title in and then add an icon in as well. Here is my code and here are some screenshots to better help with what I'm trying to achieve. I've looked through the documentation, and I've also looked at the props for the navigation drawer. Hoping someone has a good workaround.
code:
<template>
<v-card height="100%" flat>
<v-app-bar elevation="0" class="transparent">
<v-app-bar-nav-icon #click="drawer = true"></v-app-bar-nav-icon>
<v-toolbar-title>{{ Title }}</v-toolbar-title>
</v-app-bar>
<v-navigation-drawer prepend v-model="drawer" absolute temporary>
<v-list nav dense>
<v-list-item-group
v-model="group"
active-class="blue--text text--accent-4"
>
<v-list-item #click="setTitle(TitleList[0])" to="/home">
<v-list-item-icon>
<v-icon>mdi-home</v-icon>
</v-list-item-icon>
<v-list-item-title>Home</v-list-item-title>
</v-list-item>
<v-list-item #click="setTitle(TitleList[1])" to="/about">
<v-list-item-icon>
<v-icon>mdi-account</v-icon>
</v-list-item-icon>
<v-list-item-title>About</v-list-item-title>
</v-list-item>
<v-list-item #click="setTitle(TitleList[2])" to="/investments">
<v-list-item-icon>
<v-icon>mdi-currency-usd</v-icon>
</v-list-item-icon>
<v-list-item-title>Investments</v-list-item-title>
</v-list-item>
<v-list-item #click="setTitle(TitleList[3])" to="/contact">
<v-list-item-icon>
<v-icon>mdi-email</v-icon>
</v-list-item-icon>
<v-list-item-title>Contact</v-list-item-title>
</v-list-item>
</v-list-item-group>
</v-list>
</v-navigation-drawer>
<v-divider></v-divider>
<router-view></router-view>
</v-card>
</template>
<script>
export default {
data() {
return {
drawer: false,
group: null,
Title: "Home",
TitleList: ["Home", "About", "Investments", "Contact"],
};
},
methods: {
setTitle(value) {
this.Title = value;
},
},
};
</script>
I think you're problem will be solved if do not passing absolute prop for v-navigation-drawer.

Vuetify - Prevent v-list-item-group De-selection

I have a v-list and v-list-item-group setup very similar to the one shown here in the Vuetify help:
https://vuetifyjs.com/en/components/lists/#flat
My problem comes if the user clicks on the same v-list-item twice - which then de-selects it without selecting another item.
I've tried mapping the v-model to a computed get(), set() and stopping the set, but this doesn't have any effect.
I really want the selected item to be set programmatically and I control it from an #click event.
Have you tried to use the mandatory property of v-list-item-group? It seems to do something close to what you want - the user cannot de-select an item, but can switch to another one. Something like this:
<v-card class="mx-auto" max-width="300" tile>
<v-list flat>
<v-subheader>REPORTS</v-subheader>
<v-list-item-group v-model="selectedItem" color="primary" mandatory>
<v-list-item v-for="(item, i) in items" :key="i">
<v-list-item-icon>
<v-icon v-text="item.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="item.text"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
First when user select one item value of selected Item Group is changed to new value and when double click still item is selected and active.
Something like this:
<v-list-item-group
v-model="selectedItemGroup"
:mandatory="selectedItemGroup!=-1"
>
</v-list-item-group>
<script>
export default {
data:function(){
selectedItemGroup:-1,
}
}
</script>

Unable to change vuetify's card/navigation drawer's height and colour

I'm having a difficult time setting the height to match size of the browser window and setting the color of vuetify's card.
I've copied the example code from vuetiy as show below:
<template>
<v-card
class="mx-auto"
height="400"
width="256"
>
<v-navigation-drawer
class="deep-purple accent-4"
dark
permanent
>
<v-list>
<v-list-item
v-for="item in items"
:key="item.title"
link
>
<v-list-item-icon>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
<template v-slot:append>
<div class="pa-2">
<v-btn block>
Logout
</v-btn>
</div>
</template>
</v-navigation-drawer>
</v-card>
</template>
<script>
export default {
data () {
return {
items: [
{ title: 'Dashboard', icon: 'mdi-view-dashboard' },
{ title: 'Account', icon: 'mdi-account-box' },
{ title: 'Admin', icon: 'mdi-gavel' },
],
}
},
}
</script>
But the colour doesn't show up as purple. Instead it's showing as dark grey. If I remove the dark attribute in v-navigation-drawer then it just appears white.
Changing the v-card's height to 100% seems to just change the card's height to 100 instead of 100%. I'm really confused as from what I can see here, How to set the height of vuetify card, having
<v-card
height=100%
>
would have fixed the issue but it doesn't. I must be missing something simple?
So I did end up able to modify change the height and the colour although I'm not sure why it can't be done within the card tag.
In the navigation drawer I made some changes as shown below and the color as well as the height changed.
<v-navigation-drawer
class="accent-4"
width="200"
height="100vh"
color="rgba(56, 95, 115,0.5)"
permanent
>
I also removed the v-card tag completely.

v-list in v-list not working with vuetify

I am trying to implement list in list using vuetify. But I didnt manage to make it work. Below is the code and sample data. Please help me make it work. I am using vuetify 2.3.10. If I comment out the part for the second list then the first list works
<template>
<div>
<v-toolbar id="filter">
<v-layout row wrap>
<v-flex xs12 md1>
<v-menu attach="#filter-users" offset-y>
<template v-slot:activator="{ on, attrs }">
<div class="dropdown" v-bind="attrs" v-on="on">User</div>
</template>
<v-list id="filter-users">
<v-list-item
v-for="search_user in search_users"
#click="filterUser({user: search_user})">
<v-list-item-title>{{ search_user.name }}</v-list-item-title>
</v-list-item>
<v-list v-if="search_user.sub_users.length">
<v-list-item v-for="(search_sub_users, index) in search_user.sub_users"
:key="`sub_user_${index}`"
#click="filterUsers({user: search_sub_user})">
<v-list-item-title>{{ search_sub_user.name }}</v-list-item-title>
</v-list-item>
</v-list>
</v-list>
</v-menu>
</v-flex>
</v-layout>
</v-toolbar>
</div>
</template>
search_users demo data
search_users:[{
name: 'James',
sub_users: [
{
name: 'Willy'
},
{
name: 'Jack'
},
}]
},
name: 'Rock',
sub_users: [
{
name: 'Randy'
},
{
name: 'Amy'
},
}]
],
There's a lot of things going on in your code so let me enumerate them for you:
On your second sub-list, it can't find the search_user variable since that variable is only accessible inside the <v-list-item/>, which is outside of the <v-list/>.
What you can do is to create a <template/> that will wrap both <v-list-item/> and <v-list/> then put the v-for there. Something like this:
<v-list ...>
<template v-for="(search_user, index) in search_users">
<v-list-item :key="`user_${index}`">...</v-list-item> <!-- User List -->
<v-list :key="`sub_user_${index}`">...</v-list> <!-- Sub User List -->
</template>
</v-list>
Also, don't forget the v-bind:key, or simply :key, to the v-for's child elements.
You attempt to attach the <v-menu/> to its default slot. The attach prop of <v-menu/> should be somewhere outside the <v-menu/> or inside the its activator slot. However, it should attach directly to the element in your activator slot by default so you can just omit the attach prop.
<v-menu offset-y> <!-- remove the `attach` prop -->
<template v-slot:activator="{ on, attrs }">
<div class="dropdown" v-bind="attrs" v-on="on">User</div>
</template>
<v-list>...</v-list>
</v-menu>
On your second sub-list, you mistakenly typed search_sub_user instead of search_sub_users:
v-for="(search_sub_users, index) in search_user.sub_users"` // wrong
v-for="(search_sub_user, index) in search_user.sub_users"` // right
Here is a refactored version of your code at codesandbox.

How to go to a new route by clicking in a button in Vuetify?

i'm a beginner in Vuetify , and I'm develloping my first application, and my question is :
How by clicking on the "HEREEEEEEEEEEEEEEEEE" button in the navbar list the programm will route to a file called pass.vue (which is in the same folder ) ?
<template>
<div>
<v-toolbar
dark
prominent
src="https://cdn.vuetifyjs.com/images/backgrounds/vbanner.jpg"
>
<v-app-bar-nav-icon #click.stop="drawer = !drawer"></v-app-bar-nav-icon>
<v-toolbar-title>Workers</v-toolbar-title>
</v-toolbar>
<v-navigation-drawer app
v-model="drawer"
class="deep-purple accent-4"
absolute
bottom
temporary>
<v-list
nav
dense
>
<v-list-item-group
v-model="group"
active-class="deep-purple--text text--accent-4"
>
<v-list-item>
<v-list-item-icon>
<v-icon>mdi-account</v-icon>
<router-view/>
</v-list-item-icon>
<v-list-item-title router:to="/pass.vue">HEREEEEEEEEEEEEEEEEE</v-list-item-title>
</v-list-item>
<v-list-item >
<v-list-item-icon>
<v-icon>mdi-help</v-icon>
</v-list-item-icon>
<v-list-item-title>Help</v-list-item-title>
</v-list-item>
<v-list-item >
<v-list-item-icon>
<v-icon>mdi-alarm</v-icon>
</v-list-item-icon>
<v-list-item-title>Timetable</v-list-item-title>
</v-list-item>
</v-list-item-group>
</v-list>
</v-navigation-drawer>
</div>
</template>
Thank you !
I think you are confusing Vue with pure HTML. For Vue you need to use the Vue-Router library to create routes.
For Vuetify Components, or any components in general, remember that the :to creates a clickable link, so you would want to put it in a top level component which you want your user to click ex. <v-list-item> reather than v-list-item-title
Now for your particular case, your template should look like so:
<v-list-item v-for="(item,index) in items" :key="index" :to="{name: item.link}">
<v-list-item-content>
<v-list-item-title>
{{ item.text }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
Followed by:
...
data(){
return{
items:{
text: 'HEREEEEEEEEEEEEEEEEE',
link: 'pass' // this will be a named router link
}
}
...
Now in a seperate file for your router, which if you add using the vue-cli (recommended) will be created and called router.js, add the following
{
path: '/pass',
name: 'pass', // same as passed in component
component: () => import('#/path/to/file/pass.vue')
}
Now, this ,ight be overwhelming at first, but it's actually very easy. I recommend you checkout Vue-Router's Documentation before you get back to it.
Instead of item title you can use :to in v-list-item and name must be same as defined in your routes.
<v-list-item :to="{name:'pass'}">
<v-list-item-title>HEREEEEEEEEEEEEEEEEE</v-list-item-title>
</v-list-item>
I do it in this way, note that I use :to on v-list-item instead of v-list-item-title.
<v-list-item v-for="item in items" :key="item.text" :to="item.link">
<v-list-item-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
{{ item.text }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
Example of item.link
// url
:to="/profile"
// path of Location obj
:to="{ path: '/profile' }"
// a more detail Location obj
:to="{ name: 'profile2', params: { userId: 123 }}"
You can either pass a string url to :to or a Location. Make sure you've declare this route in your router like below:
const routes = [
{
path: '/profile',
name: 'profile',
component: Profile
},
{
path: '/profile2/:userId',
name: 'profile2',
component: Profile2
}
];