Vuetify rendering v-datatable automatically - vue.js

I have a problem v-datatable rendering each time I change a v-select.
I´d like it render only when I click in a button, I created to do fetch data from server.
Here is the codepen: https://codepen.io/luizalves/pen/VwrwXwE?editors=101
For now, it´s rendering all times I change the v-select.
data:()=>({
grupos: [
{ id: 1, nome: 'Diário', ffi: 'YYYY-MM-DD', fff: 'DD-MM-YYYY' },
{ id: 2, nome: 'Mensal', ffi: 'YYYY-MM', fff: 'MM-YYYY' },
{ id: 3, nome: 'Anual', ffi: 'YYYY', fff: 'YYYY' },
],
grupo:1
headers: [
{ text: 'Data', value: 'label', sortable: false },
{ text: 'Total(R$) ', value: 'total', sortable: false },
],
)}
// data-table
<v-select
v-model="grupo"
label="Grupado por"
:items="grupos"
item-text="nome"
item-value="id"
class="purple-input"
/>
<v-btn
class="mt-1 mr-3"
color="info"
#click.stop="getEstatisticasPeriodo()"
>
Pesquisar
</v-btn>
<v-data-table
:headers="headers"
:items="result_dados"
:items-per-page="3"
:footer-props="{
'items-per-page-options': [3, 5, 10, 20, 30, 40, 50],
}"
class="elevation-1"
>
<template
v-for="(header, i) in headers"
#[`item.${header.value}`]="{ item }"
>
<template v-if="header.value !== 'actions'">
<span :key="i">
{{ formatColumn(item, header) }}
</span>
</template>
</template>
</v-data-table>
methods: {
formatColumn(item, col) {
if (!item[col.value]) return ''
if (['total'].includes(col.value)) {
const formatado = Number(item[col.value]).toLocaleString('pt-BR', {
style: 'currency',
currency: 'BRL',
})
return formatado
}
if (['label'].includes(col.value)) {
const ffi = this.grupos.find((m) => m.id == this.grupo).ffi
const fff = this.grupos.find((m) => m.id == this.grupo).fff
return this.$moment(item[col.value], ffi).format(fff)
} else return item[col.value]
},
getEstatisticasPeriodo(){
// fetch api data
}
....

Any data value you access in formatCalories will be added the list of watched values. When the value changes, it will re-render the view and call formatCalories. To solve that issue, I just created a selectValue property that is only set when the button is clicked.
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
group: 1,
selectValue: 1,
groups: [
{ id: 1, name: 'day'},
{ id: 2, name: 'month' },
{ id: 3, name: 'year' },
],
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' },
],
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%',
},
],
}
},
methods: {
onSubmit() {
this.selectValue = this.$refs.select.value;
},
formatCalories(calories) {
const suffix = {
1: '-red',
2: '-orange',
3: '-green'
};
return calories + suffix[this.selectValue];
}
},
})
<div id="app">
<v-app id="inspire">
<v-row>
<v-col cols='3'>
<v-btn elevation="2" #click="onSubmit"> Submit </v-btn>
<v-select
v-model="group"
label="Grouped by"
:items="groups"
item-text="name"
item-value="id"
class="purple-input"
ref="select"
/>
</v-col>
</v-row>
<v-data-table
:headers="headers"
:items="desserts"
class="elevation-1"
>
<template v-slot:item.calories="{ item }">
{{ formatCalories(item.calories) }}
</template>
</v-data-table>
</v-app>
</div>

Related

How to add pagination code to data table in vue js?

I'm utilizing v-data-table in a vue component, looking through the documentation it wasn't clear to me how to utilize built in pagination in the data table and how to invoke code for the pagination . I tried to look through some of the blogs but still not clear.
<template>
<v-data-table
:page="page"
:pageCount="numOfPages"
:headers="headers"
...
</template>
<script>
export default {
name: "DataTableSample",
data() {
return {
...
},
watch: {
options: {
handler() {
this.getData();
},
},
deep: true,
},
methods: {
load(){
//load data
...
},
mounted(){
this.getData();
},
};
</script>
Not sure what does this statement means it wasn't clear to me how to utilize built in pagination in the data table and how to invoke code for the pagination ?
But <v-data-table> providing pagination by default. Here is the demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
selected: [ ],
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: '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%',
}
]
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.0.0-beta.8/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#2.0.0-beta.8/dist/vuetify.min.css"/>
<div id="app">
<v-app>
<v-data-table
id="mytable"
v-model="selected"
:headers="headers"
:items="desserts"
:items-per-page="5"
class="elevation-1"
item-key="name"
>
</v-data-table>
</v-app>
</div>

Vuetify v-data-table drag and resizable columns together

I'm using vuetify v-data-table. I implement drag column with SortableJs and also column resizable.
When I drag a column, it works properly but after that the resize does not work anymore.
<div id="app">
<v-app id="inspire">
<v-data-table :headers="headers" :items="desserts"
sort-by="calories"
disable-sort
v-sortable-table="{onEnd:sortTheHeadersAndUpdateTheKey}"
:key="anIncreasingNumber" >
</v-data-table>
</v-app>
</div>
Here is my codepen
Thanks in advance.
As I can see here, the Vuetify team is not interested in doing this feature now.
Thank you for the Feature Request and interest in improving Vuetify. Unfortunately, this is not a functionality we are looking to implement now.
For now, you can check this CodepPen it will do the trick for you.
If you don't want to do it manually you could install an npm package called vue-columns-resizable-vuetify
<!-- Credit
Column Resize - Web Dev Tricks https://webdevtrick.com/resizable-table-columns/
Vuetify Datatable - Vuetify Example
https://vuetifyjs.com/en/components/data-tables/ -->
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="desserts"
class="elevation-1"
>
</v-data-table>
</v-app>
</div>
th, td {
border-right: 1px solid grey;
}
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
headers: [
{ text: 'Dessert (100g serving)', sortable: false, value: 'name'},
{ text: 'Calories', sortable: false, value: 'calories' },
{ text: 'Fat (g)', sortable: false, value: 'fat' },
{ text: 'Carbs (g)', sortable: false, value: 'carbs' },
{ text: 'Protein (g)', sortable: false, value: 'protein' },
{ text: 'Iron (%)', sortable: false, 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%',
},
],
}
},
})
var tables = document.getElementsByTagName('table');
for (var i=0; i<tables.length;i++){
resizableGrid(tables[i]);
}
function resizableGrid(table) {
var row = table.getElementsByTagName('tr')[0],
cols = row ? row.children : undefined;
if (!cols) return;
table.style.overflow = 'hidden';
var tableHeight = table.offsetHeight;
for (var i=0;i<cols.length;i++){
var div = createDiv(tableHeight);
cols[i].appendChild(div);
cols[i].style.position = 'relative';
setListeners(div);
}
function setListeners(div){
var pageX,curCol,nxtCol,curColWidth,nxtColWidth;
div.addEventListener('mousedown', function (e) {
curCol = e.target.parentElement;
nxtCol = curCol.nextElementSibling;
pageX = e.pageX;
var padding = paddingDiff(curCol);
curColWidth = curCol.offsetWidth - padding;
if (nxtCol)
nxtColWidth = nxtCol.offsetWidth - padding;
});
div.addEventListener('mouseover', function (e) {
e.target.style.borderRight = '2px solid #0000ff';
})
div.addEventListener('mouseout', function (e) {
e.target.style.borderRight = '';
})
document.addEventListener('mousemove', function (e) {
if (curCol) {
var diffX = e.pageX - pageX;
if (nxtCol)
nxtCol.style.width = (nxtColWidth - (diffX))+'px';
curCol.style.width = (curColWidth + diffX)+'px';
}
});
document.addEventListener('mouseup', function (e) {
curCol = undefined;
nxtCol = undefined;
pageX = undefined;
nxtColWidth = undefined;
curColWidth = undefined
});
}
function createDiv(height){
var div = document.createElement('div');
div.style.top = 0;
div.style.right = 0;
div.style.width = '5px';
div.style.position = 'absolute';
div.style.cursor = 'col-resize';
div.style.userSelect = 'none';
div.style.height = height + 'px';
return div;
}
function paddingDiff(col){
if (getStyleVal(col,'box-sizing') == 'border-box'){
return 0;
}
var padLeft = getStyleVal(col,'padding-left');
var padRight = getStyleVal(col,'padding-right');
return (parseInt(padLeft) + parseInt(padRight));
}
function getStyleVal(elm,css){
return (window.getComputedStyle(elm, null).getPropertyValue(css))
}
};

Vuetify data table get selected item

I have a v-data-table that has Show-select,
I want to get the data of what items I selected, at least alert the first column value upon check
. Im searching everywhere. i cant find answer to my problem.
<div id="app">
<v-app id="inspire">
<v-data-table
:value="selected"
#input="enterSelect($event)"
:items-per-page="itemsPerPage"
:headers="headers"
:items="desserts"
item-key="name"
show-select
class="elevation-1"
>
</v-data-table>
<v-dialog>
<v-card>
</v-card>
</v-dialog>
</v-app>
</div>
js
new Vue({
el: '#app',
vuetify: new Vuetify(),
methods: {
enterSelect(values) {
if (values.length == this.itemsPerPage) {
alert('selected all')
}
}
},
data () {
return {
selected: [],
itemsPerPage: 10,
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: '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%',
},
],
}
},
})
https://codepen.io/CodingDeer/pen/QWLyaog?editors=1010
this is just an example of what I recently found (code not mine),
this code can detect if all checkbox selected
Use v-model instead of :value to allow modification of selected variable when you try to select some items. Then check the this.selected's length inside the enterSelect function.
<v-data-table
v-model="selected"
#input="enterSelect()"
...
>...</v-data-table>
methods: {
enterSelect() {
console.log(this.selected.map(e => e.name)); // logs all the selected items.
if (this.selected.length == this.itemsPerPage) {
alert('selected all')
}
}
}
For example you want to get the names of the rows, here's how to get them.
methods: {
enterSelect(values) {
var names = values.map(function(value){ return value.name })
console.log(names)
}
}

Vuetify v-data-table double click event does not work

I'm using a v-data-table.
According to official library, it has a dblclick:row event.
I tried to use it, but doesn't work.
(click:row event works fine.)
vuetify version is latest vuetify#2.3.8.
how can I use double click event in v-data-table?
here is my code sample.
(sorry for didn't write full code. I added. )
<div id="app">
<v-app id="inspire">
<v-card>
<v-data-table
:items="items"
:headers="headers"
dense
v-model="selected"
hide-default-footer
#click:row="clickRow"
#dblclick:row="dblclickRow"
>
</v-data-table>
</v-card>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
selected: [],
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" }
],
items: [
{
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%"
}
],
selected:[]
}),
methods: {
dblclickRow(){
console.log("rowDoubleClicked");
},
clickRow(){
// console.log("rowClicked");
}
}
})
Your functions should be under methods. See this link https://v2.vuejs.org/v2/guide/events.html#Method-Event-Handlers.
The event is not reaching your function

Exclude disabled item in V-Data-Table's select-all [VUETIFY]

I have v-data-table with disabled item and want to exclude it when I trigger the select-all in header.data-table-select slot. Also applied :readonly but still get checked.
<template v-slot:item.data-table-select="{ item, isSelected, select }">
<v-simple-checkbox
:value="isSelected"
:readonly="item.name == 'Frozen Yogurt'"
:disabled="item.name == 'Frozen Yogurt'"
#input="select($event)"
></v-simple-checkbox>
</template>
Also looked at the docs and found this header.data-table-select slot but only gives me this options:
{
props: {
value: boolean
indeterminate: boolean
},
on: {
input: (value: boolean) => void
}
}
Is there any way of handling selected items in v-data-table?
Here's the live code: https://d4et5.csb.app/
EDITED
CodeSandBox: https://codesandbox.io/s/festive-haze-d4et5
It is possible to remove disabled item form a select all in datatable
I've added a new key "disabled" in items array
Here is the working codepen:
https://codepen.io/chansv/pen/mdJMvJr?editors=1010
<div id="app">
<v-app id="inspire">
<v-data-table
v-model="selected"
:headers="headers"
:items="desserts"
item-key="name"
show-select
class="elevation-1"
#toggle-select-all="selectAllToggle"
>
<template v-slot:item.data-table-select="{ item, isSelected, select }">
<v-simple-checkbox
:value="isSelected"
:readonly="item.disabled"
:disabled="item.disabled"
#input="select($event)"
></v-simple-checkbox>
</template>
</v-data-table>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
selected: [],
disabledCount: 0,
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' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
disabled: true,
},
{
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%',
disabled: true,
},
{
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%',
},
],
}
},
methods: {
selectAllToggle(props) {
if(this.selected.length != this.desserts.length - this.disabledCount) {
this.selected = [];
const self = this;
props.items.forEach(item => {
if(!item.disabled) {
self.selected.push(item);
}
});
} else this.selected = [];
}
},
created() {
const self = this;
this.desserts.map(item => {
if (item.disabled) self.disabledCount += 1
})
}
})
On tops chans' answer. if you have pagination with your datatable, and you have multiple pages of data, the answer probably won't work for you. instead of calculating disabledCount i calculate if selected items length is equal to all available items length
selectAllToggle(props) {
let availableItems = props.items.filter(item => !item.isDisabled)
if (this.selected.length !== availableItems.length) {
this.selected = availableItems;
} else {
this.selected = [];
}
}
Just One simple change will work. You have to change the value attribute v-simple-checkbox.
<template v-slot:item.data-table-select="{ item, isSelected, select }">
<v-simple-checkbox
:value="(item.name !== 'Frozen Yogurt') && isSelected"
:readonly="item.name == 'Frozen Yogurt'"
:disabled="item.name == 'Frozen Yogurt'"
#input="select($event)"
></v-simple-checkbox>
</template>