Get selection of vuetify list - vue.js

How do I get the selected item / index of from a vuetify list?
Applying v-model to the <v-list> tag does not work somehow and I can not find any working example.
I'd like to have a list of images / file names and then display the selected image. My idea was to have an <v-img :src="imgpath"> and then imgpath beeing a reactive state that is changed via the list. Or is my idea completely wrong?
Minimum example of my try:
<template>
<v-app>
<v-main>
<v-card>
<v-list v-model='selection' :items='items'></v-list>
</v-card>
<v-card class='mt-5'>
{{ selection }}
</v-card>
</v-main>
</v-app>
</template>
<script>
export default {
data: () => ({
selection: 1,
items: [
{ title: 'Item 0', value: 0 },
{ title: 'Item 1', value: 1 },
{ title: 'Item 2', value: 2 },
],
}),
}
</script>
Expected behaviour:
The selection state changes according to the selected item in the list.
Observed behaviour:
Visually the selection changes (a different item is marked with a gray background), but the selection does not change.

You can add v-list-item in a loop. On <v-list-item> add #click handler to update selection data. Try this:
<template>
<v-app>
<v-main>
<v-card>
<v-list>
<v-list-item
v-for="(item, index) in items"
:key="index"
#click="selection = index"
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
<v-card class="mt-5">
{{ selection }}
</v-card>
</v-main>
</v-app>
</template>
<script>
export default {
data: () => ({
selection: 0,
items: [
{ title: "Item 0", value: 0 },
{ title: "Item 1", value: 1 },
{ title: "Item 2", value: 2 },
],
}),
};
</script>

Related

Vuetify <v-list-item-group> v-model mutliple selecting doesnt work

<v-list shaped>
<v-navigation-drawer>
<v-list shaped>
<v-list-item-group
v-model="selectedItem"
multiple
>
<template v-for="(item, i) in items">
<v-list-item
:value="item"
>
<v-list-item-title>{{item.text}}</v-list-item-title>
</v-list-item>
</template>
</v-list-item-group>
</v-list>
</v-navigation-drawer>
data: () => ({
selectedItem: 0,
drawer: null,
items: [
{ icon: 'fas fa-home', text: 'Dashboard', route: '/home' },
{ icon: 'fas fa-money-check-alt', text: 'Invoices', route: '/invoices' },
{ icon: 'fas fa-dolly', text: 'Partners', route: '/partners' },
{ icon: 'fas fa-exchange-alt', text: 'Items', route: '/items' },
],
}),
Very simple code in vuetify (2.6.1),multiple selecting doesnt work,
I can't preselect first item to be selected too. Its probably related to v-list-item-group component.
There are 2 mistakes in your code:
when you are using multiple prop, a selectedItem should be an array;
when you are applying :value="item", your selectedItem array should contain the whole object instead of its index.
So your code should be:
...
<v-list-item-group
v-model="selectedItem"
multiple
>
<template v-for="(item, i) in items">
<v-list-item>
<v-list-item-title>{{item.text}}</v-list-item-title>
</v-list-item>
</template>
</v-list-item-group>
...
data: () => ({
items: [
...
],
selectedItem: [0],
}),
...

Vuetify table - add hyperlink to column

In my vue component I am using vuetify table. It works properly, but I need to make that click on items in column "Category name" redirect to vue view which shows details of clicked item (I need to forward item id to view which shows details of item). I don`t know how to do that?
In method 'editItem' I also need to redirect to other page, with forwarded id, I also don`t know how to do that?
I tried to make "Category name" items as hyperlink, but it does not work and it is without id:
<template v-slot:item.categoryName="{ item }">
<a :href="this.$router.push({name: 'EditCategory'})">{{item.categoryName}}</a>
</template>
This is code of my vue component 'CategoryTable':
<template>
<v-data-table
:headers="headers"
:items="categories"
sort-by="categoryName"
class="elevation-1"
:footer-props="{
'items-per-page-options': [1, 2, 3, 4, 5]
}"
:items-per-page="2"
>
<template v-slot:top>
<v-toolbar
flat
>
<v-toolbar-title>Categories Table</v-toolbar-title>
<v-divider
class="mx-4"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<button #click="$router.push({name: 'AddCategory'})">Add category</button>
</v-toolbar>
</template>
<template v-slot:item.actions="{ item }">
<v-icon
small
class="mr-2"
#click="editItem(item)"
>
mdi-pencil
</v-icon>
<v-icon
small
#click="deleteItem(item)"
>
mdi-delete
</v-icon>
</template>
</v-data-table>
</template>
<script>
export default {
name: "CategoriesTable",
data: () => ({
headers: [
{
text: 'Category name',
align: 'start',
value: 'categoryName',
},
{ text: 'Description', value: 'description' },
{ text: 'Actions', value: 'actions', sortable: false },
],
categories: [],
editedIndex: -1,
defaultItem: {
id: 0,
categoryName: '',
description: '',
},
}),
created () {
this.initialize()
},
methods: {
initialize () {
this.$axios.get('/api/categories').then((response) => {
console.log(response.data)
this.categories = response.data;
});
},
editItem (item) {
this.$router.push({name: 'CategoryEdit'});
item.id
},
deleteItem (item) {
this.$axios.delete('/api/categories/' + item.id).then((response) => {
console.log(response)
});
},
},
}
</script>
If you want the user to be redirected after clicking on a particular category name, you will pass the corresponding route or id like i did below:
<v-data-table
:headers="headers"
:items="categories"
sort-by="categoryName"
class="elevation-1"
:footer-props="{
'items-per-page-options': [1, 2, 3, 4, 5],
}"
:items-per-page="2"
>
<template v-slot:item.categoryName="{ item }">
<a
#click="$router.push(`/details/${item.itemID}`)"
>
{{item.categoryName}}
</a>
</template>
</v-data-table>
the item id is passed after clicking on the category

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 insert action button in data-table and get row data

Environment:
vue#^2.6.10:
vuetify#^2.1.0
I want to use v-data-table to show search results and add evaluate button in each row in the v-data-table.
Unfortunately I have two issues:
Evaluate buttons are not shown
I don't know how to get row data of pushed button
What do I need to change?
Template
<v-data-table
:headers="headers"
:items="search_result"
>
<template slot="items" slot-scope="row">
<td>{{row.item.no}}</td>
<td>{{row.item.result}}</td>
<td>
<v-btn class="mx-2" fab dark small color="pink">
<v-icon dark>mdi-heart</v-icon>
</v-btn>
</td>
</template>
</v-data-table>
Script
data () {
return {
headers: [
{ text: 'no', value: 'no' },
{ text: 'result', value: 'result' },
{ text: 'good', value: 'good'},
],
// in real case initial search_result = [], and methods: search function inject below data
search_result: [{no: 0, result: 'aaa'}, {no:2, result: 'bbb'],
}
},
slot name used to "replace the default rendering of a row" is item, not items
Add wrapping <tr> into slot template
Just add #click="onButtonClick(row.item) to v-btn and create method onButtonClick
<v-data-table :headers="headers" :items="search_result">
<template v-slot:item="row">
<tr>
<td>{{row.item.no}}</td>
<td>{{row.item.result}}</td>
<td>
<v-btn class="mx-2" fab dark small color="pink" #click="onButtonClick(row.item)">
<v-icon dark>mdi-heart</v-icon>
</v-btn>
</td>
</tr>
</template>
</v-data-table>
methods: {
onButtonClick(item) {
console.log('click on ' + item.no)
}
}
Note..
...solution above is replacing default row rendering with your own so expect some of the v-data-table features to not work (didn't try but I expect row selection, grouping, in place editing etc. will be broken). If that's problem for you, here is alternative solution:
Add one more column to your headers definition: { text: "", value: "controls", sortable: false }
Do not override item slot (row rendering). Override item.controls slot instead. Notice "controls" is the same as in column definition - we are overriding just rendering of "controls" column
Everything else is same
<v-data-table :headers="headers" :items="search_result">
<template v-slot:item.controls="props">
<v-btn class="mx-2" fab dark small color="pink" #click="onButtonClick(props.item)">
<v-icon dark>mdi-heart</v-icon>
</v-btn>
</template>
</v-data-table>
In my case the solution of Michal was throwing the following exception
The solution was using slot and slot-scope
<template>
<v-data-table
:headers="headers"
:items="items"
class="elevation-1"
>
<template slot="item.delete" slot-scope="props">
<v-btn class="mx-2" icon #click="() => delete(props.item)">
<v-icon dark>mdi-delete</v-icon>
</v-btn>
</template>
</v-data-table>
</template>
<script>
export default {
data() {
return {
headers: [
// Dynamic headers
{
text: 'Name',
value: 'name'
},
{
text: '',
// Row to replace the original template
value: 'delete'
},
],
items: [
{
id: 1,
name: 'A'
},
{
id: 2,
name: 'B'
}
]
};
},
methods: {
delete(item) {
this.items = this.items.filter((d) => d.id !== item.id);
},
},
};
</script>

Parent Vuetify VMenu Not Closing When Child Selected

My app creates it's main navigation dynamically via for loops to generated nested vmenu's and vlists. It generates correctly. The problem is when a user clicks a link in a nested menu, the parent menu remains open. I've tried close-on-click and close-on-content-click on both the main and nested menu, but that's not working.
My codepen has a simplified example. If you select MENU 1, then hover over Subitem 1-1 and click on Subitem 1-1-1, that immediate menu closes, but the main menu remains open.
My codepen.
<div id="app">
<v-app id="inspire">
<v-container>
<!-- top level menu -->
<v-menu
v-for="(menu,index) in menus"
:key="`menu-${index}`"
offset-y
close-on-click
#click="route()"
>
<v-btn
flat
primary
slot="activator"
>{{ menu.title }}</v-btn>
<!-- each item on a menu .. is a menuitem -->
<v-list dense>
<v-list-tile
v-for="(menuitem,index) in menu.items"
:key="`menuitem-${index}`"
#click="route()"
>
<!-- or a popout of submenu items -->
<v-list-tile-content>
<v-menu
offset-x
open-on-hover
close-on-click
>
<v-list-tile
slot="activator"
#click="route()"
>
<v-list-tile-title>{{ menuitem.title }}</v-list-tile-title>
<v-list-tile-action
class="justify-end"
v-if="menuitem.items"
>
<v-icon primary>arrow_right</v-icon>
</v-list-tile-action>
</v-list-tile>
<v-list
dense
v-if="menuitem.items"
>
<v-list-tile
v-for="(menusubitem,index) in menuitem.items"
:key="`menusubitem-${index}`"
#click="route()"
>
<v-list-tile-title>{{ menusubitem.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-menu>
</v-container>
</v-app>
</div>
And the related script.
new Vue({
el: '#app',
data: () => ({
menus: [
{
title: 'MENU 1',
items: [
{ title: 'Subitem 1-1',
items: [
{ title: 'Subitem 1-1-1' },
{ title: 'Subitem 1-1-2' }
]
},
{ title: 'Subitem 1-2' },
{ title: 'Subitem 1-3' }
]
},
{
title: 'MENU 2',
},
{
title: 'MENU 3',
items: [
{ title: 'Subitem 3-1' },
{ title: 'Subitem 3-2' },
]
}]
}),
methods: {
route() {
console.log("replace with router")
}
}
})
One option would be to access and close parent menu explicitly via isActive property:
route(parentMenuIndex) {
if (arguments.length) {
const parentMenu = this.$refs.menuRef[parentMenuIndex];
parentMenu.isActive = false;
}
}
where this.$refs.menuRef is used to access parent menu component via the ref attribute:
<v-menu
v-for="(menu,index) in menus"
:key="`menu-${index}`"
offset-y
close-on-click
close-on-content-click
ref="menuRef"
>
...
</v-menu>
Here is an updated CodePen