Cannot expand or collapse v-list veutify - vue.js

I am having issues with Vuetify v-list and v-list-group, I am trying to make a list and it does not expand nor collapse, I have tried to modify it myself and tried to copy and paste (from here https://next.vuetifyjs.com/en/components/lists/#sub-group, this also adding necessary props and models) but nothing. Not sure what I am doing wrong, I am not sure if it's the v-slot not working. I am using vite with vue 3 and vuetify 3.
<template>
<v-card class="mx-auto" width="300">
<v-list v-model:opened="open">
<v-list-item prepend-icon="mdi-home" title="Home"></v-list-item>
<v-list-group value="Users">
<template v-slot:activator>
<v-list-item prepend-icon="mdi-account-circle" title="Users"></v-list-item>
</template>
<v-list-group value="Admin">
<template v-slot:activator>
<v-list-item title="Admin"></v-list-item>
</template>
<v-list-item v-for="([title], i) in admins" :key="i" :title="title" :value="title"></v-list-item>
</v-list-group>
<v-list-group value="Actions">
<template v-slot:activator>
<v-list-item title="Actions"></v-list-item>
</template>
<v-list-item v-for="([title], i) in cruds" :key="i" :value="title" :title="title"></v-list-item>
</v-list-group>
</v-list-group>
</v-list>
</v-card>
</template>
<script lang="ts" setup>
import { createVuetify } from 'vuetify'
import { ref, computed } from 'vue'
import { useDisplay } from 'vuetify'
const open = ['Users'];
const admins = [
['Management', 'mdi-account-multiple-outline'],
['Settings', 'mdi-cog-outline'],
];
const cruds = [
['Create', 'mdi-plus-outline'],
['Read', 'mdi-file-outline'],
['Update', 'mdi-update'],
['Delete', 'mdi-delete'],
];
const links = ['Hi', 'Contacts', 'Settings', 'Hi', 'Contacts', 'Settings', 'Hi'];
const buttonLinks = ['Hi', 'Contacts', 'Settings', 'Hi', 'Contacts', 'Settings', 'Hi', 'Contacts', 'Settings', 'Hi', 'Contacts', 'Settings', 'Hi', 'Contacts', 'Settings', 'Hi', 'Contacts', 'Settings', 'Hi', 'Contacts', 'Settings', 'Hi', 'Contacts', 'Settings'];
const mini = true;
const items = [
{ title: 'Hello', icon: 'mdi-view-dashboard' },
{ title: 'About', icon: 'mdi-forum' },
];
</script>

Found the answer, and once again hopefully the Veutify team will post more appropriate examples of their library
<template>
<v-card class="mx-auto" width="300">
<v-list>
<v-list-item prepend-icon="mdi-home" title="Home"></v-list-item>
<v-list-group value="Users">
<template v-slot:activator="{ props }">
<v-list-item v-bind="props" prepend-icon="mdi-account-circle" title="Users"></v-list-item>
</template>
<v-list-group value="Admin">
<template v-slot:activator="{ props }">
<v-list-item v-bind="props" title="Admin"></v-list-item>
</template>
<v-list-item v-for="(title, i) in admins" :key="i" :title="title" :value="title">
</v-list-item>
</v-list-group>
<v-list-group value="Actions">
<template v-slot:activator="{ props }">
<v-list-item v-bind="props" title="Actions"></v-list-item>
</template>
<v-list-item v-for="(title, i) in cruds" :key="i" :value="title" :title="title">
</v-list-item>
</v-list-group>
</v-list-group>
</v-list>
</v-card>
</template>
Notice how I removed the <v-list v-model:opened="open"> from <v-list> that was the main problem, even if you don't pass in props and create a temporary array this will work and your list will collapse and expand

Related

Vuetify v-menu open a submenu

I would like to divide this menu into submenu I cannot divide these items below
This menu I will call router as functions
I searched on google and I didn't understand how I do this for with the sub-menu
<div id="v-menu">
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn outlined color="blue" dark v-bind="attrs" v-on="on">
<v-icon left small>mdi-cogs</v-icon> Mais Ações<v-icon
color="black"
right
medium
>mdi-chevron-down</v-icon
>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(item, index) in itemsmenuRel"
:key="index"
router
:to="item.link"
style="max-height: 0px"
>
<v-list-item-title>
<v-icon left small>{{ item.icon }}</v-icon
>{{ item.title }}</v-list-item-title
>
</v-list-item>
</v-list>
</v-menu>
</div>
This is an example of an array
itemsmenuRel: [
{
title: "Menu1",
icon: "mdi-file-cog-outline",
subLinks: [
{ text: "Add Manager1", route: "/managers/add" },
{ text: "Managers2", route: "/managers" },
],
},
{
title: "Menu2",
icon: "mdi-image-filter-drama",
subLinks: [
{ text: "Add Manager3", route: "/managers/add" },
{ text: "Managers4", route: "/managers" },
],
},
],

After adding 1 item to TODO app fails when I just type on text field, How to fix it?

this might be stupitest question to ask but I just can't understand why this is happening , I am trying to Build simple TODO app with Nuxt Js with Vuex, When I add one Item it works fine and displays, after that if I just type something on text field app failds and gives error
"Error: [vuex] do not mutate vuex store state outside mutation handlers."
Here is index.vue file
<template>
<v-main>
<v-row justify="center" class="py-10">
<h1 class="teal--text">NUXT TODO APP</h1>
<v-col cols="12" md="10">
<v-text-field type="text" outlined v-model="item.text"> </v-text-field>
<v-btn color="teal" x-large class="mt-3" #click="addItem">Add</v-btn>
</v-col>
<v-col cols="8">
<h1 v-if="items.length <= 0">No Data Found</h1>
<v-list v-else>
<v-list-item v-for="item in items" :key="item.id" class="my-5">
<v-list-item-content>
<v-list-item-title>{{ item.text }}</v-list-item-title>
</v-list-item-content>
<v-list-item-action class="d-flex flex-row">
<v-btn color="teal"> Edit </v-btn>
<v-btn color="error" class="mx-5"> Delete </v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
</v-col>
</v-row>
</v-main>
</template>
<script>
export default {
computed: {
items() {
return this.$store.state.items;
},
},
data: () => ({
item: {
text: "",
},
}),
methods: {
addItem() {
this.$store.commit("addItem", this.item);
},
},
};
</script>
And here is index.js file for Vuex
export const state = () => ({
items: [],
});
export const mutations = {
addItem(state, payload) {
state.items.push(payload);
},
};
please guide me what the hell I am missing here.
Thank You.

Vuejs sidebar menu with subitems

I am trying to create a sidebar menu dinamically with vuejs and vuenotify.
I have seen a sample on vuetify site using something as bellow.
The problem with this code, is that always shows the append-icon ">" on end of item title .
I´d like to show the append-icon ">", only if I have subittems.
I have created an item called "Manuutenção" with subtitems. No other has subitems.
Then, i´d like only "Manutençao" item or other(if I create with subitems") showing the ">".
Is possible fix it?
<v-list>
<v-list-group
v-for="item in items"
:key="item.title"
v-model="item.active"
:prepend-icon="item.icon"
no-action
>
<template v-slot:activator>
<v-list-item-content>
<v-list-item-title v-text="item.title"></v-list-item-title>
</v-list-item-content>
</template>
<v-list-item
v-for="subItem in item.items"
:key="subItem.title"
link
router
:to="subItem.to"
>
<v-list-item-content>
<v-list-item-title v-text="subItem.title"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-group>
</v-list>
export default {
name: "DashboardCoreDrawer",
data: () => ({
items: [
{
icon: "mdi-view-dashboard",
title: "Dashboard",
to: "/",
},
{
icon: "mdi-account",
title: "Usuários",
to: "/usuarios",
},
{
title: "Clientes",
icon: "mdi-map-marker",
to: "/clientes",
},
{
title: "Manutenção",
icon: "mdi-clipboard-outline",
to: "",
items: [
{
title: "Convênios",
icon: "mdi-clipboard-outline",
to: "/convenios",
},
{
title: "Planos",
icon: "mdi-format-font",
to: "/planos",
},
],
},
{
title: "Convênios",
icon: "mdi-clipboard-outline",
to: "/convenios",
},
{
title: "Planos",
icon: "mdi-format-font",
to: "/planos",
},
{
title: "Tabelas",
icon: "mdi-chart-bubble",
to: "/tabelas",
},
{
title: "Atendimento",
icon: "mdi-bell",
to: "atendimentos",
},
],
}),
}
Additional information:
Is possible make adaptations to two or three submenu items. For sample:
items:[
{
title: "Manutenção",
icon: "mdi-clipboard-outline",
to: "",
items: [
{
title: "Convênios",
icon: "mdi-clipboard-outline",
to: "/convenios",
},
{
title: "Planos",
icon: "mdi-format-font",
to: "",
items: [
{
title: "Test1,
icon: "mdi-chart-bubble",
to: "/test1",
},
{
title: "Test2",
icon: "mdi-chart-bubble",
to: "/test2",
},
],
},
]
Icon at "Planos"
The main trick is to render v-list-group when item has subitems and v-list-item otherwise. See an example below:
<template>
<v-list>
<template v-for="item in items">
<v-list-group
:key="item.title"
v-if="item.items !== undefined"
v-model="item.active"
no-action
>
<template v-slot:activator>
<v-list-item-avatar left>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="item.title"></v-list-item-title>
</v-list-item-content>
</template>
<v-list-item
v-for="subItem in item.items"
:key="subItem.title"
link
router
:to="subItem.to"
>
<v-list-item-avatar left>
<v-icon>{{ subItem.icon }}</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="subItem.title"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-group>
<v-list-item v-else :key="item.title" link router :to="item.to">
<v-list-item-avatar left>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="item.title"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
</v-list>
</template>
Edited:
For a multilevel solution, basically, you have to create a component for list item and import it recursively into itself. Something like that:
mainlist.vue
<template>
<div>
<v-list>
<list-item v-for="item in items" :item="item" :key="item.title">
</list-item>
</v-list>
</div>
</template>
<script>
export default {
name: "DashboardCoreDrawer",
components: {
ListItem: () => import("./listitem.vue"),
},
data: () => ({
items: [
{
title: "Convênios",
icon: "mdi-clipboard-outline",
to: "/convenios",
},
{
title: "Planos",
icon: "mdi-format-font",
items: [
{
title: "Test1",
icon: "mdi-chart-bubble",
items: [
{
title: "Test4",
icon: "mdi-chart-bubble",
to: "/test1",
},
{
title: "Test5",
icon: "mdi-chart-bubble",
to: "/test2",
},
],
},
{
title: "Test2",
icon: "mdi-chart-bubble",
to: "/test2",
},
],
},
],
}),
};
</script>
listitem.vue
<template>
<div>
<v-list-group
v-if="item.items !== undefined"
v-model="item.active"
no-action
:sub-group="isSubGroup"
:class="isSubGroup ? 'right-icon' : ''"
>
<template v-slot:activator>
<v-list-item-content>
<v-list-item-title>
<v-icon>{{ item.icon }}</v-icon>{{ item.title }}
</v-list-item-title>
</v-list-item-content>
</template>
<template v-for="subItem in item.items">
<list-item :item="subItem" :is-sub-group="true" :key="subItem.title">
</list-item>
</template>
</v-list-group>
<v-list-item v-else link router :to="item.to">
<v-list-item-avatar left>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="item.title"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</div>
</template>
<script>
export default {
name: "listitem",
props: ["item", "isSubGroup"],
components: {
ListItem: () => import("./listitem.vue"),
},
};
</script>
<style>
.right-icon .v-list-group__header {
display: flex !important;
flex-direction: row-reverse !important;
}
</style>

How do I overcome error 'Avoid using JavaScript keyword as "v-on" value'

How do I get rid of this error in my App.vue component?
Failed to compile.
./src/App.vue
Module Error (from ./node_modules/eslint-loader/index.js):
C:\xampp2\htdocs\exchproto\src\App.vue
15:69 error Avoid using JavaScript keyword as "v-on" value: "" vue/valid-v-on
✖ 1 problem (1 error, 0 warnings)
I tested the whole code (including sub-components) with CDN pull of vuejs/vuetify css/js etc and all worked well. This error only comes up as I am breaking down the code into components and doing everything by "yarn install". Been poking at it for some time with no luck.
<template>
<v-app>
<v-app-bar app>
<v-app-bar-nav-icon #click="drawer = !drawer"></v-app-bar-nav-icon>
<v-spacer></v-spacer>
<v-menu :offset-y="true">
<template v-slot:activator="{ on }">
<v-btn icon v-on="on">
<v-icon>mdi-dots-horizontal</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item v-for="(item, i) in rightMenuitems" :key="i" #click="">
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-app-bar>
<!--router-view></!--router-view-->
</v-app>
</template>
<script>
export default {
name: 'App',
components: {},
data() {
return {
drawer: false,
rightMenuitems: [
{ title: 'Choice 1' },
{ title: 'Choice 2' },
{ title: 'Choice 3' },
{ title: 'Choice 4' }
],
}
}
}
</script>
You can't have an empty #click="" You must have the click point to a function:
<v-list-item
v-for="(item, i) in rightMenuitems"
:key="i"
#click="doSomething($event, i)"
>
<v-list-item-title>
{{ item.title }}
</v-list-item-title>
</v-list-item>
// ...
methods: {
someFunction(event, i) {
console.log("clicked item " + i);
}
}
// ...
Remove 'click event' and add to property in v-list-item where v-for is being used.
Note:
You can bind links with the to props, and also links in every objects of rightMenuitems.
Here is an example:

Vuetify router alignment

I'm trying to setup at route that contains just a table with a layout inspired by the Vuetify team.
I have a problem that the table does not take only a small part of the screen.
I have tried using v-layout with "row", "column" and different paddings and marging.
App.vue:
<template>
<v-app>
<router-view/>
</v-app>
</template>
<script>
export default {
name: 'App',
};
</script>
Menu.vue:
<template>
<v-container>
<v-navigation-drawer
clipped
fixed
v-model="drawer"
app
>
<v-list dense>
<v-list-tile
:to="{name: 'dashboard'}"
>
<v-list-tile-action>
<v-icon>dashboard</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Dashboard</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile
:to="{name: 'settings'}"
>
<v-list-tile-action>
<v-icon>settings</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Settings</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile
#click="logout();"
>
<v-list-tile-action>
<v-icon>logout</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Logout</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<v-toolbar app fixed clipped-left>
<v-toolbar-side-icon #click.stop="drawer = !drawer"></v-toolbar-side-icon>
<v-toolbar-title>Hello, {{ name }}</v-toolbar-title>
</v-toolbar>
<v-content>
<v-container fluid fill-height>
<v-layout justify-center align-center>
<v-flex shrink>
<router-view></router-view>
</v-flex>
</v-layout>
</v-container>
</v-content>
<v-footer app fixed>
<span>© arcyfelix 2019</span>
</v-footer>
</v-container>
</template>
<script>
export default {
name: 'MainMenu',
data() {
return {
drawer: false,
name: 'Wojciech',
};
},
methods: {
logout() {
this.$router.push({ name: 'home' });
},
},
};
</script>
Dashboard.vue:
<template>
<v-layout full-width>
<v-data-table
:items="desserts"
class="elevation-1"
hide-actions
hide-headers
expand
:loading="true"
>
<template v-slot:items="props">
<td class="text-xs-left">2019-07-01</td>
<td>{{ props.item.name }}</td>
<td>
<v-btn
small
depressed
flat
>
Edit
</v-btn>
</td>
</template>
</v-data-table>
</v-layout>
</template>
<script>
export default {
name: 'Dashboard',
data() {
return {
desserts: [
{
name: 'Frozen Yogurt',
},
{
name: 'Donut',
},
{
name: 'KitKat',
},
],
};
},
};
</script>
router.js:
import Vue from 'vue';
import Router from 'vue-router';
import Menu from './layouts/Menu.vue';
import MainMenu from './layouts/MainMenu.vue';
import Dashboard from './views/Dashboard.vue';
import Login from './views/Login.vue';
import Home from './views/Home.vue';
Vue.use(Router);
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: 'auth',
name: 'auth',
component: Menu,
children: [
{
path: 'dashboard',
name: 'dashboard',
component: Dashboard,
},
{
path: 'settings',
name: 'settings',
component: () => import(/* webpackChunkName: "about" */ './views/Settings.vue'),
},
],
},
{
path: '/',
name: 'mainMenu',
component: MainMenu,
children: [
{
path: 'home',
name: 'home',
component: Home,
},
{
path: 'login',
name: 'login',
component: Login,
},
{
path: 'register',
name: 'register',
component: () => import(/* webpackChunkName: "about" */ './views/Register.vue'),
},
],
},
],
});
I would like to take it 2/3 or full width of the screen.
What you really want is to put the menu outside of the router-view otherwise it has to reload on each page load. You also want to move the container definition inside of the v-content element and make sure it uses fill-height too less you end up with an odd background mesh.
<v-app>
<my-menu></my-menu>
<v-content>
<v-container fluid fill-height>
<router-view></router-view>
</v-container>
</v-content>
</v-app>
Now just change your Dashboard code and layout:
<v-layout row wrap>
<v-flex xs12>
//the rest of the dashboard code
</v-flex>
</v-layout
And you're good to go.