Duplicate click event in v-data-table with action buttons column - vue.js

In vuetify I want to display item data when any part of the row is clicked or delete an item if a button in the row is clicked.
However, if I click the delete button the two events fire. I tried using #click:row.self='viewItem' but that doesn't seem to work.
<template>
<v-data-table
dense
:headers="headers"
:items="desserts"
item-key="name"
class="elevation-1"
#click:row.self="viewItem" //this fires when the delete button is clicked
>
<template v-slot:item.actions="{ item }">
<v-icon small #click="viewItem(item)">mdi-export</v-icon> //see item details
<v-icon small class="mr-2" #click="confirmDeleteOfItem(item)">mdi-delete</v-icon> //delete item
</template>
</v-data-table>
</template>
<script>
export default {
data: () => ({
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
},
],
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
],
}),
}
</script>

No, the problem is in your item.actions slot - you need to stop click event bubbling from your icons to a table row when your icon is clicked, try this:
<template v-slot:item.actions="{ item }">
<v-icon small #click.stop="viewItem(item)">mdi-export</v-icon>
<v-icon small class="mr-2" #click.stop="confirmDeleteOfItem(item)">mdi-delete</v-icon>
</template>

Related

Get selection of vuetify list

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>

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 to add icon to the Header in vuetify DataTable

I'm trying to add (+) icon to the one of the header columns in v-datatable.
The code below does not add any icon. Actually, creating template slot for header does not have any effect on datatable.
What I try,
<template>
<v-data-table
item-key="name"
:items="complainantInfos"
:headers="headers"
sort-by="Id"
class="elevation-1">
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>Inspection</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
</template>
<template slot="headers" slot-scope="props">
<tr>
<th
v-for="header in props.headers"
:key="header.text">
<v-icon small >plus-circle-outline</v-icon>
{{ header.text }}
</th>
</tr>
</template>
</v-data-table>
</template>
<script>
import { mapGetters } from "vuex";
export default {
data(){
return{
complainantInfos:[
{
...
}
],
headers: [
{ text: 'NameSurname', value: 'name', align: 'left' ,width: "25%" },
{ text: 'ID', value: 'PersonelIdNumber' },
{ text: 'Phone-1', value: 'Cellular1' },
{ text: 'Phone-2', value: 'Cellular2' },
{ text: 'Work Phone', value: 'WorkPhone' },
{ text: 'InterPhone', value: 'Interphone' },
{ text: 'Email', value: 'Email' },
//{ text: '+', value: 'action', sortable: false, align: 'right'}
],
I have edited the code according to the comments. The problem solved.
...
</v-card>
</v-form>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:header.Actions="{ header }">
<v-icon small>plus-circle-outline</v-icon>{{ header.text }}
</template>
...
Since you only wish to add the icon to one specific column, I would suggest header.columnName.
Your slot would look like this:
<template v-slot:header.name="{ header }">
<v-icon small>plus-circle-outline</v-icon>{{ header.text }}
</template>
If the column name is "Cellular1", the code will be <template v-slot:header.Cellular1="{ header }">.
Please make sure you have the icon set included. Otherwise, no HTML will be rendered for v-icon. You can test it with default mdi icons, for example mdi-minus.

How to combine an Expandable Table with an Expansion Panel in Vuetify?

I'd like to combine two separate Vuetify functionalities into one:
https://vuetifyjs.com/en/components/data-tables --> Expandable Rows Table (but ideally with more than one data row upon expansion)
https://vuetifyjs.com/en/components/expansion-panels --> External Control Expansion Panel
Ultimately, the goal is to have a table that looks like this (Grouping Table with expand/collapse all one): https://codepen.io/lzhoucs/pen/aadaJx
The issue with this table is that despite fitting the code into my project, certain functionalities don't work -- such as clicking to open and close a table. I believe this is due to this being a different version of Vue than what I'm using, which is the most up to date, as I spotted some old styles.
I've tried a bunch of things, but my most successful attempt is creating a table within a table. Here is the code for that:
<template>
<v-container>
<v-data-table
:headers="headers"
:items="projects"
:expanded="expanded"
item-key="name"
show-expand
class="elevation-1"
#click:row="clicked"
>
<template v-slot:expanded-item="{ headers }">
<td :colspan="headers.length">
<v-data-table
:headers="peopleHeaders"
:items="people"
item-key='name'
hide-default-footer
class='elevation-1'>
<template slot="item" slot-scope="props">
<tr>
<td>{{props.item.name}}</td>
<td>{{props.item.major}}</td>
<td>{{props.item.preference}}</td>
<td>
<v-btn color='success'>Accept</v-btn>
<v-btn color='error'>Reject</v-btn>
</td>
</tr>
</template>
</v-data-table>
</td>
</template>
</v-data-table>
</v-container>
</template>
<script>
export default {
data() {
return {
expanded: [],
headers: [
{
text: 'Name',
align: 'left',
sortable: true,
value: 'name',
},
{ text: 'Status', value: 'Status' },
],
projects: [
{
name: '#this is the project they applied to',
Status: 'Status: Pending',
},
],
peopleHeaders: [
{
text: 'Name',
align: 'left',
sortable: true,
value: 'name',
},
{
text: 'Major',
align: 'left',
sortable: true,
value: 'major',
},
{
text: 'Preference',
align: 'left',
sortable: true,
value: 'preference',
},
],
people: [
{
name: 'BORB',
major: 'SWE',
preference: 'idk',
},
],
};
},
methods: {
clicked(value) {
this.expanded.push(value);
},
},
};
</script>
Any advice for how to combine the two features to achieve the table desired would be greatly appreciated.

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>