I am working with v-data-table and trying to add a new column that is calories and divided it by fat. I am trying to set up the new column name, but have been unable to figure it out.
I know that using
<template v-slot:item.fat="{item}">
<span>test1</span>
</template>
Will change what is put in the fat column, but how do I create a new column?
Here is a link to my code https://codepen.io/aaronk488/pen/vYePVoZ?editors=101
Check this codepen I made: https://codepen.io/cmfc31/pen/dyVrQNz?editors=101
You have to define the new column in your headers array.
headers: [
{
text: "Dessert (100g serving)",
align: "start",
value: "name"
},
{
text: "My new column",
align: "start",
value: "mynewcol"
},
...
Then you can use/modify it with the item slot in your datatable, like this.
<v-data-table
:headers="headers"
:items="desserts"
item-key="name"
class="elevation-1"
>
<template v-slot:item.mynewcol="{ item, index }">
{{ 'Test ' + index }}
</template>
</v-data-table>
Related
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>
I have a Vue application which is built using Vuetify and I want to create a table where cell content is a checkbox v-checkbox but it renders html string instead of checkbox inside table body.
I use v-data-table as a main table.
For illustration:
My Code:
<v-data-table :headers="headers"
:items="menuaccess"
:search="search"
sort-by="alias"
class="elevation-3"
v-html="value"> <--- I tried add this but not working
<!-- other code -->
Data source snippet (I will get data from API later) :
headers: [
{ text: '', align: 'start', value: 'alias' },
{ text: 'ASSET_EDIT', value: '<v-checkbox class="mx-2" label="Example"></v-checkbox>' },
{ text: 'ASSET_VERIFICATION', value: '<v-checkbox class="mx-2" label="Example"></v-checkbox>' },
{ text: 'ASSET_VIEW', value: '<v-checkbox class="mx-2" label="Example"></v-checkbox>' },
{ text: 'CUSTOMER_COMPANY_EDIT', value: '<v-checkbox class="mx-2" label="Example"></v-checkbox>' },
],
You need to place code inside slot template.
<v-data-table :headers="headers"
:items="menuaccess"
:search="search"
sort-by="alias"
class="elevation-3">
<template v-slot:item.property_name="{ item }">
<v-simple-checkbox v-model="item.property_name" />
</template>
</v-data-table>
Where property_name is name of the property on your data object.
Read more about it in the documentation.
I am using a Vuetify data table and I am using v-slot:item on two of the columns to insert switches.
<v-data-table
:headers="headers"
:items="records"
:search="search"
:items-per-page="5"
>
<template v-slot:item.monitor="{ item }">
<v-switch v-model="item.monitor" color="success"></v-switch>
</template>
<template v-slot:item.manage="{ item }">
<v-switch v-model="item.manage" color="success"></v-switch>
</template>
</v-data-table>
What I want to do is set the switches like an Item Group so that only one may be selected (on) at a time, but both can be false (off). So only one can have a true value.
I have tried using the Item Group component and got that to work, but I am not sure if it is even possible within the table the way I want since these two switches are in separate slots. I am under the impression that the v-item should be sibling components, so that makes me think that would't work for this situation.
The way I see it, there are two different approches to this problem. You can either:
Watch the records array to detect changes in either monitor or manage attributes of one of its objects.
Do not use v-model directive on the switches but provide a readonly value, then change it manually on click.
I prefer the second option. You can do it like so:
Template section
<div id="app">
<v-app id="inspire">
<v-data-table :headers="headers" :items="records">
<template v-slot:item.monitor="{ item }">
<v-switch
:input-value="item.monitor"
readonly
color="success"
#click.stop="setSwitchesForItem(item.id, 'monitor', !item.monitor)"
/>
</template>
<template v-slot:item.manage="{ item }">
<v-switch
:input-value="item.manage"
readonly
color="success"
#click.stop="setSwitchesForItem(item.id, 'manage', !item.manage)"
/>
</template>
</v-data-table>
</v-app>
</div>
A couple of things to note here:
v-model has been replaced by :input-value
readonly props has been set
the click event calls a custom method. It requires the .stop suffix because of a bug documented here
Script section
export default {
// ...
data() {
return {
headers: [
{ text: "Name", value: "name" },
{ text: "Monitor", value: "monitor" },
{ text: "Manage", value: "manage" }
],
records: [
{
id: 1,
name: "Item 1",
monitor: true,
manage: false
},
{
id: 2,
name: "Item 2",
monitor: false,
manage: true
},
{
id: 3,
name: "Item 3",
monitor: false,
manage: false
}
]
};
},
methods: {
setSwitchesForItem(itemId, attributeName, attributeValue) {
const record = this.records.find(r => r.id === itemId);
// In case the new value is true, we need to make sure the other one is set to false
if (attributeValue) {
record[attributeName === "monitor" ? "manage" : "monitor"] = false;
}
record[attributeName] = attributeValue;
}
}
}
Link to the Codepen.
I'm learning Vue and Vuetify at the moment and I've faced the problem of indexing rows in data tables.
The only way I can assign the number of a row is relying on indexOf comparing to the raw array of data.
But the problem in my case is that when I sort data in the table index breaks accordingly.
I would like to have it stable and when you sort data it recalculates.
Is there any way to achieve it in Vue?
In Angular it's much easier with tables. There is a build-in functionality
Or maybe you know how to reach the filtered or sorted data (array) where Vue holds it.
<v-data-table
:headers="headers"
:items="orders"
class="elevation-2 mt-4"
:loading="loading"
loading-text="Loading... Please wait"
>
<template v-slot:item.index="{ item }">
{{ orders.indexOf(item) + 1}}
</template>
</v-data-table>
Thanks in advance!
The way I've managed to get it working (thanks to #elushnikova) is like this:
<v-data-table
:headers="headers"
:items="orders"
class="elevation-2 mt-4"
:loading="loading"
loading-text="Loading... Please wait"
>
<template v-slot:item="{item, index}">
<tr>
<td>{{index + 1}}</td>
<td>{{item.client_name}}</td>
<td>{{item.client_id}}</td>
<td>{{item.order_total}}</td>
</tr>
</template>
</v-data-table>
It doesn't break on sorting. But I believe later I'll have another problem with it when I have pagination.
But let's solve problems as they come :)
I found this in this link
<template #item.index="{ item }">
{{ protocolData.indexOf(item) }}
</template>
and its worked for me.
Closest way to get the result is by using a computed property as show in codepen
https://codepen.io/manojkmishra/pen/OJyYzVo
Template Part:
<div id="app">
<v-app>
<h3>Orders</h3>
<v-data-table
:headers="headers"
:items="ordersWithIndex"/>
</v-app>
</div>
Script Part:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
headers: [{ text: 'Num', value: 'index' },
{ text: 'OrderName', value: 'Name' },
{ text: 'OrderValue', value: 'value' }
],
orders: [ {Name: 'order1', value: 100 },
{ Name: 'order2', value: 200 },
{ Name: 'order3', value: 300 },
{ Name: 'order4', value: 400 }
],
}
},
computed: {
ordersWithIndex()
{ return this.orders.map(
(items, index) => ({
...items,
index: index + 1
}))
}
}
})
This can be achieved in vuetify using item. slot, you need to pass a header for index along with other headers (eg. SNO).
now just use this in v-data-table.
<template v-slot:item.SNO = "{ index }">
{{ index + 1 }}
</template>
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>