Vuetify select dropdown inside datatable creating position issue - css

I'm using Vuetify datatable having 20 columns. It is working as expected. If the datatable has many columns, with the help of horizontal scrolling we can view all the columns
I want filters for each column in header, used v-slot:header and achieved that too.
The issue i'm facing right-now is when we click on select box, the dropdown opens, at the same time, when you do horizontal scrolling. The position of dropdown is not sticky with the select box, it just hanged in screen
The codepen to produce this issue: https://codepen.io/chansv/pen/OJygmjL
Steps to reprodcue:
open the above codepen
click on select box in header
make the dropdown open
now scroll the datatable horizontally using side arrow
The dropdown is not sticks to the select box
This problem is not with vertical scrolling, only in horizontal scrolling this issue exist
If anyone experienced the same, suggest me some idea to fix this
Here is the code:
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="5"
class="elevation-1"
hide-default-header
>
<template v-slot:header="{ props }">
<th v-for="(head, index) in props.headers" :key="index"><div>{{head.text}}</div>
<div>
<v-select :items="items" placeholder="select from items"></v-select>
</div>
</th>
</template>
</v-data-table>
</v-app>
</div>
th {
min-width: 250px;
}
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
items: [
"dessert",
"calories",
"iron",
"fat"
],
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
})
Thanks in advance

I've solved this issue by adding attach prop to
https://codepen.io/jkarczm/pen/XWmgajJ
<v-select attach :items="items" placeholder="select from items"></v-select>

Related

vuetify changing font colors of data-table

I am struggling to find ways to change font-colors in data-table. I found ways to change color of headers and rows, but now I need to change the color of rows-per-page count selecter box (it is filled with black font, but selector box is white and fonts are black) and also < > arrow bars for page spans are left black but I want them white
<template>
<div class="container fill">
<BootstrapNavBar></BootstrapNavBar>
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="5"
class="mytable red yellow--text"
></v-data-table>
</div>
</template>
<script>
import BootstrapNavBar from "./BootstrapNavBar.vue";
import axios from "axios";
export default {
components: {
BootstrapNavBar,
},
data() {
return {
itemsPerPage: 5,
headers: [
{
text: "Dessert (100g serving)",
align: "start",
sortable: false,
value: "name",
class: "white--text",
},
{ text: "Calories", value: "calories", class: "white--text" },
{ text: "Fat (g)", value: "fat", class: "white--text" },
{ text: "Carbs (g)", value: "carbs", class: "white--text" },
{ text: "Protein (g)", value: "protein", class: "white--text" },
{ text: "Iron (%)", value: "iron", class: "white--text" },
],
desserts: [
{
name: "Frozen Yogurt",
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: "1%",
},
],
balances: [],
};
},
methods: {},
};
</script>
<style scoped>
.fill {
color: #e5e6e7;
min-height: 100%;
height: 100%;
}
.theme--light.v-data-table {
background-color: #282c30 !important;
color: rgb(255, 255, 255) !important;
}
</style>
Red parts trying to make white font
Selector box when clicked it is black fonts over white, and selected part is all white. I need here black background, and white fonts, selected one could be another color
also why is my data-table, grayish color. Is it possible to align it with the background fill color.
Can you please try to play around with the classes mapped to the footer elements and then update the styles using custom CSS. Something like this :
i.mdi-chevron-left, i.mdi-chevron-right, i.mdi-menu-down {
color: white !important;
}
.v-select__selections {
color: white !important;
}
Demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
headers: [
{
text: 'Dessert (100g serving)',
align: 'left',
sortable: false,
value: 'name',
class: 'success--text title',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
})
.theme--light.v-data-table {
background-color: #282c30 !important;
color: rgb(255, 255, 255) !important;
}
i.mdi-chevron-left, i.mdi-chevron-right, i.mdi-menu-down {
color: white !important;
}
.v-select__selections {
color: white !important;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.1.5/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#2.1.5/dist/vuetify.min.css"/>
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="5"
class="elevation-1"
></v-data-table>
</v-app>
</div>

Vuetify Data Table Slide Transition

I'm trying to animate the data on a Vuetify data table. My goal is to have the current data slide out to the right when Next is clicked, and have the new data slide in from the left.
Here is my current result:
As you can see, the current data is sliding out, but the new data is appearing at the bottom and sliding up when the old data is out.
Here's my code:
<v-data-table
:headers="headers"
:items="scoreResults"
disable-sort
hide-default-footer
:mobile-breakpoint="0"
>
<template v-slot:body="{ items }">
<tbody name="list" is="transition-group">
<tr v-for="item in items" :key="item.id" class="item-row">
<td>{{item.player}}</td>
<td>{{item.total_score}}</td>
<td><v-chip
:dark="item.points > 5 ? true : false"
:color="getColor(item.points)"
>+{{ item.points }}</v-chip>
</td>
<td><em>{{item.guess}}</em></td>
</tr>
</tbody>
</template>
</v-data-table>
and CSS
.list-enter-active,
.list-leave-active {
transition: all 0.8s;
}
.list-enter {
opacity: 0;
transform: translateX(10%);
}
.list-leave-to {
opacity: 0;
transform: translateX(100%);
}
.list-move {
transition: transform 0.5s;
}
.item-row {
display: table-row;
}
How do I get the new data to appear from the left, and slide in as the old data leaves?
The problem is the current table rows get added to the table when old rows are leaving. To solve that I used translateY to move the rows. There are still some issues with some transitions ending, while others start.
const root = document.documentElement;
const TRANSITION_DURATION = 800;
// Copied From https://www.joshwcomeau.com/snippets/javascript/debounce/
const debounce = (callback, wait) => {
let timeoutId = null;
return (...args) => {
window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
callback.apply(null, args);
}, wait);
};
}
new Vue({
el: '#app',
vuetify: new Vuetify(),
created() {
this.onAfterLeave = debounce(this.onAfterLeave, TRANSITION_DURATION);
},
computed : {
totalNumItems() {
return this.desserts.length;
}
},
mounted() {
this.tableEl = this.$refs.dataTable.$el.querySelector('table');
},
methods: {
onPagination() {
this.lastTransitionTime = Date.now();
if(!this.tableEl
|| this.isUpdatingItems
||this.isTransitioning) {
this.isUpdatingItems = false;
return;
}
this.isTransitioning = true;
this.tableHeight = this.tableEl.offsetHeight;
},
onUpdateItems(numItems) {
let cssNumItems = numItems;
this.isUpdatingItems = true;
if (numItems === this.totalNumItems) {
cssNumItems = 0;
}
root.style.setProperty('--num-items', cssNumItems);
},
onAfterLeave(el) {
if (Date.now() - this.lastTransitionTime < TRANSITION_DURATION) {
window.setTimeout(this.onAfterLeave.bind(this, el), TRANSITION_DURATION);
} else {
this.isTransitioning = false;
this.tableHeight = 'unset';
}
}
},
data () {
return {
search: '',
msg: 'No Results Here!',
tableHeight: 'unset',
lastTransitionTime: 0,
numItems: 5,
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
})
:root {
--num-items: 5;
--row-y: calc(var(--num-items) * -100%);
}
#app {
padding: 20px;
}
table,
.v-data-table__wrapper {
overflow: hidden !important;
}
#keyframes slide-in {
0% {
opacity: 0;
transform: translateX(-100%) translateY(var(--row-y));
}
100% {
opacity: 1;
transform: translateX(0) translateY(var(--row-y));
}
}
.list-enter-to {
animation: slide-in .8s;
}
.list-leave-active {
opacity: 1;
transform: translateX(0);
transition: all .7s .1s;
}
.list-leave-to {
opacity: 0;
transform: translateX(100%);
}
<div id="app">
<v-app id="inspire">
<v-card>
<v-card-title>
<v-text-field v-model="search"
append-icon="search"
label="Search"
single-line hide-details>
</v-text-field>
</v-card-title>
<v-data-table :headers="headers"
:height="tableHeight"
:items="desserts"
:search="search"
:items-per-page="5"
item-key="name"
#pagination="onPagination"
#update:items-per-page="onUpdateItems"
ref="dataTable" >
<template v-slot:body="{items, headers}">
<tbody name="list"
is="transition-group"
v-on:after-leave="onAfterLeave">
<tr v-for="item in items"
:key="item.name"
class="item-row">
<td>{{item.name}}</td>
<td>{{item.calories}}</td>
<td>{{item.fat}}</td>
<td>{{item.carbs}}</td>
<td>{{item.protein}}</td>
<td>{{item.iron}}</td>
</tr>
</tbody>
</template>
</v-data-table>
</v-card>
</v-app>
</div>

v-menu attach not working inside vuetify datatable header filter

Steps to reproduce
In the codepen there are two different datepicker used, when data is
present the datepicker is showing as expected, if the table is empty
while filtering, datepicker hides inside datatable
Expected Behavior
The datepicker should be showing outside the footer instead of hides
inside the table
Actual Behavior
When attach is used it should be sticky to the datepicker input box,
so that when horizontal scrolling happens, datepicker will also scroll
along with input box.
At the same time, when no data is present in table both select
dropdown options and datepicker hides inside the table. Tried the
z-index for footer as well as datepicker. It didn't worked . Is this a
bug or is there any other way to handle this case
Reproduction Link
https://codepen.io/chansv/pen/XWmamRP?editors=1000
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="5"
class="elevation-1"
hide-default-header
>
<template v-slot:header="{ props }">
<th v-for="(head, index) in props.headers" :key="index"><div>{{head.text}}</div>
<div v-if="index != 1 && index != 2">
<v-select attach :items="items" placeholder="select with attach"></v-select>
</div>
<div style="position: relative;">
<div v-if="index === 1" id="foo" style="position: absolute;">
<v-menu
attach="#foo"
ref="menu"
v-model="menu"
:close-on-content-click="false"
:return-value.sync="date"
transition="scale-transition"
offset-y
min-width="290px"
>
<template v-slot:activator="{ on }">
<v-text-field
v-model="date"
label="Picker with attach"
prepend-icon="event"
readonly
v-on="on"
></v-text-field>
</template>
<v-date-picker v-model="date" no-title scrollable>
<v-spacer></v-spacer>
<v-btn text color="primary" #click="menu = false">Cancel</v-btn>
<v-btn text color="primary" #click="$refs.menu.save(date)">OK</v-btn>
</v-date-picker>
</v-menu>
</div>
</div>
<div v-if="index === 2" >
<v-menu
ref="menu1"
v-model="menu1"
:close-on-content-click="false"
:return-value.sync="date"
transition="scale-transition"
offset-y
min-width="290px"
>
<template v-slot:activator="{ on }">
<v-text-field
v-model="date1"
label="picker without attach"
prepend-icon="event"
readonly
v-on="on"
></v-text-field>
</template>
<v-date-picker v-model="date1" no-title scrollable>
<v-spacer></v-spacer>
<v-btn text color="primary" #click="menu1 = false">Cancel</v-btn>
<v-btn text color="primary" #click="$refs.menu1.save(date1)">OK</v-btn>
</v-date-picker>
</v-menu>
</div>
</th>
</template>
</v-data-table>
</v-app>
</div>
th {
min-width: 250px;
}
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
date: new Date().toISOString().substr(0, 10),
menu: false,
date1: new Date().toISOString().substr(0, 10),
menu1: false,
items: [
"dessert",
"calories",
"iron",
"fat"
],
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [],
desserts1: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
})

Vuetify Datatables Cells Text not vertically center aligned

I am trying vuetify on laravel vue application, everything seems okay except datatables styles, padding of cells is not center aligned vertically. Here is screenshot
The same code works fine in codepen, here is the link
new Vue({
el: '#app',
data: () => ({
dialog: false,
headers: [
{
text: 'Dessert (100g serving)',
align: 'left',
sortable: false,
value: 'name'
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Actions', value: 'name', sortable: false }
],
desserts: [],
editedIndex: -1,
editedItem: {
name: '',
calories: 0,
fat: 0,
carbs: 0,
protein: 0
},
defaultItem: {
name: '',
calories: 0,
fat: 0,
carbs: 0,
protein: 0
}
}),
computed: {
formTitle () {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
}
},
watch: {
dialog (val) {
val || this.close()
}
},
created () {
this.initialize()
},
methods: {
initialize () {
this.desserts = [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7
}
]
},
editItem (item) {
this.editedIndex = this.desserts.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialog = true
},
deleteItem (item) {
const index = this.desserts.indexOf(item)
confirm('Are you sure you want to delete this item?') && this.desserts.splice(index, 1)
},
close () {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
save () {
if (this.editedIndex > -1) {
Object.assign(this.desserts[this.editedIndex], this.editedItem)
} else {
this.desserts.push(this.editedItem)
}
this.close()
}
}
})
<div id="app">
<v-app id="inspire">
<div>
<v-dialog v-model="dialog" max-width="500px">
<v-btn slot="activator" color="primary" dark class="mb-2">New Item</v-btn>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container grid-list-md>
<v-layout wrap>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.name" label="Dessert name"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.calories" label="Calories"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.fat" label="Fat (g)"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.carbs" label="Carbs (g)"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.protein" label="Protein (g)"></v-text-field>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" flat #click.native="close">Cancel</v-btn>
<v-btn color="blue darken-1" flat #click.native="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-data-table :headers="headers" :items="desserts" hide-actions class="elevation-1">
<template slot="items" slot-scope="props">
<td>{{ props.item.name }}</td>
<td class="text-xs-right">{{ props.item.calories }}</td>
<td class="text-xs-right">{{ props.item.fat }}</td>
<td class="text-xs-right">{{ props.item.carbs }}</td>
<td class="text-xs-right">{{ props.item.protein }}</td>
<td class="justify-center layout px-0">
<v-btn icon class="mx-0" #click="editItem(props.item)">
<v-icon color="teal">edit</v-icon>
</v-btn>
<v-btn icon class="mx-0" #click="deleteItem(props.item)">
<v-icon color="pink">delete</v-icon>
</v-btn>
</td>
</template>
<template slot="no-data">
<v-btn color="primary" #click="initialize">Reset</v-btn>
</template>
</v-data-table>
</div>
</v-app>
</div>
https://codepen.io/anon/pen/OEZjrV?&editors=101
The issue seems to be a conflict with bootstrap, is there a way to fix this? The same with problem also bulma
if you want to set your table with center align , change this on your td class class="text-xs-right"with class="text-xs-center". and add some props in your headers with align: 'center'

Computed properties in Vuetify Datatable rows

I am using Vuetify and Vuetify/Datatables for a website.
Now I want some computed properties on every row of the table.
To do that I would probably need to make a component of the <template> element and add computed properties to that component. I tried <template is="myComponent" :m="props.item"> but this did not work.
<v-data-table
:headers="headers"
:items="items"
hide-actions
class="elevation-1"
>
<template slot="items" slot-scope="props">
<td>{{ THIS_VALUE_COMPUTED }}</td>
<td class="text-xs-right">{{ props.item.calories }}</td>
<td class="text-xs-right">{{ props.item.fat }}</td>
<td class="text-xs-right">{{ props.item.carbs }}</td>
<td class="text-xs-right">{{ props.item.protein }}</td>
<td class="text-xs-right">{{ props.item.iron }}</td>
</template>
</v-data-table>
it's a bit aged question but this might work, it is from the vuetify 2.0.19 documentation. Here you can do a computed value on one of the single properties of your table.
<v-data-table
:headers="headers"
:items="items"
hide-actions
class="elevation-1"
>
<template
v-slot:item.calories="{ item }" >
{{ THIS_VALUE_COMPUTED }}
</template>
</v-data-table>
I was able to use computed properties by including an extra component (with computed properties) and an extra <template> element. I am not realy happy with havign two <template> elements inside each other but this was the only way to get this working. Any better solutions are still very welcome.
(Working codepen example)
JS (a modification on the Vuetify Datatable example):
let myComponent = Vue.component('my-component', {
props: {
item: {
type: Object,
required: true,
}
},
mounted: function() {
console.log('mounted', this.item)
},
computed: {
COMPUTED_PROPERTY: function() {
return this.item.fat +
this.item.carbs +
this.item.protein
}
},
template: `<tr>
<td>{{ item.name }}</td>
<td>{{ item.calories }}</td>
<td>{{ COMPUTED_PROPERTY }}</td>
<td>{{ item.iron }}</td>
</tr>`
})
new Vue({
el: '#app',
mounted: function() {
console.log('loaded')
},
components: { myComponent },
data: () => ({
pagination: {
sortBy: 'name'
},
selected: [],
headers: [
{
text: 'Dessert (100g serving)',
align: 'left',
value: 'name'
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat + Carbs + Protein (g)', value: 'total' },
{ text: 'Iron (%)', value: 'iron' }
],
items: [
{
value: false,
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%'
},
{
value: false,
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%'
},
{
value: false,
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%'
},
{
value: false,
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%'
},
{
value: false,
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%'
},
{
value: false,
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%'
},
{
value: false,
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%'
},
{
value: false,
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%'
},
{
value: false,
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%'
},
{
value: false,
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%'
}
]
}),
methods: {
changeSort (column) {
if (this.pagination.sortBy === column) {
this.pagination.descending = !this.pagination.descending
} else {
this.pagination.sortBy = column
this.pagination.descending = false
}
}
}
})
HTML:
<div id="app">
<v-app id="inspire">
<v-data-table
v-model="selected"
:headers="headers"
:items="items"
select-all
:pagination.sync="pagination"
item-key="name"
class="elevation-1"
>
<template slot="headers" slot-scope="props">
<tr>
<th
v-for="header in props.headers"
:key="header.text"
:class="['column sortable', pagination.descending ? 'desc' : 'asc', header.value === pagination.sortBy ? 'active' : '']"
#click="changeSort(header.value)"
>
<v-icon small>arrow_upward</v-icon>
{{ header.text }}
</th>
</tr>
</template>
<template slot="items" slot-scope="props">
<template :active="props.selected" #click="props.selected = !props.selected">
<my-component :item="props.item">
</my-component>
</template>
</template>
</v-data-table>
</v-app>
</div>

Resources