I'm using quasar framework dataTable component inside another component (EmployeeComponent) but I want to change style of the table. if i change style inside EmployeeComponent, I need to rewrite style or include it everytime I want to use quasar table inside any another component. So I put quasar component inside another component (TableComponent) and change style just one time and include it wherever I want.
Here is quasar dataTable component:
<q-table
title="Table Title"
:data="tableData"
:columns="columns"
:rows-per-page-options=[1,2]
:selection="selection"
:selected.sync="selected"
row-key="name"
/>
it takes two main props (data, columns) which will be optaind from Tablecomponent
<table-component :tableThs="tableThs" :tableTds="tableTds"></table-component>
Tablecomponent will take data from EmployeeComponent. I make it worked in case of passing static data, see code below:
EmployeeComponent
<template>
<table-component :tableThs="tableThs" :tableTds="tableTds"></table-
component>
</template>
<script>
export default {
data: () =>({
tableThs: [
{
name: 'desc',
required: true,
label: 'Dessert (100g serving)',
align: 'left',
field: 'name',
sortable: true
},
{
name: 'desc1',
required: true,
label: 'Calories',
align: 'left',
field: 'calories',
sortable: true
},
{
name: 'desc2',
required: true,
label: 'Carbs',
align: 'left',
field: 'carbs',
sortable: true
},
{
name: 'desc3',
required: true,
label: 'Protein',
align: 'left',
field: 'protein',
sortable: true
},
{
name: 'desc4',
required: true,
label: 'Sodium',
align: 'left',
field: 'sodium',
sortable: true
},
{
name: 'desc5',
required: true,
label: 'Calcium',
align: 'left',
field: 'calcium',
sortable: true
},
{
name: 'desc6',
required: true,
label: 'Iron',
align: 'left',
field: 'iron',
sortable: true
}
],
tableTds: [
{
name: 'Frozen Yogurt',
calories: 19,
fat: 6.0,
carbs: 24,
protein: 4.0,
sodium: 87,
calcium: '14%',
iron: '1%'
},
{
name: 'Frozen Yogurt1',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
sodium: 87,
calcium: '14%',
iron: '1%'
},
,
{
name: 'Frozen Yogurt2',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
sodium: 87,
calcium: '14%',
iron: '1%'
},
,
{
name: 'Frozen Yogurt3',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
sodium: 87,
calcium: '14%',
iron: '1%'
},
,
{
name: 'Frozen Yogurt4',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
sodium: 87,
calcium: '14%',
iron: '1%'
},
]
}),
mounted() {
}
}
TableComponent
<template>
<q-table
title="Table Title"
:data="tableData"
:columns="columns"
:rows-per-page-options=[1,2]
:selection="selection"
:selected.sync="selected"
row-key="name"
/>
</template>
<script>
export default {
props: ['tableThs', 'tableTds'],
data: () =>({
columns: [],
tableData: [],
selection: 'multiple',
selected: [
// initial selection; notice we specify the
// row-key prop of the selected row
{ name: 'Ice cream sandwich' }
]
}),
beforeMount() {
this.columns = this.tableThs;
this.tableData = this.tableTds;
}
}
</script>
<style>
.row{
margin-left: 0;
margin-right: 0;
}
.q-table-bottom{
border-top: 0;
}
</style>
The problem is it is not worked when passing data in employee component by axios request.
Related
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>
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>
I have a Vuetify data table that is refreshed from the server every 5 seconds. It has selectable rows. If you select a row, then something in the data changes, the v-model array of selected items does not reflect the changes inside the row items. This codepen is a slightly modified version of a Vuetify example:
https://codepen.io/hobbeschild/pen/bGqGMQQ?editors=1010
Select the first row. At the top you will see the time in the selected item. Wait 5 seconds for the data to refresh. You will see that the selected item time does not match the row item time anymore.
Is there a way to ensure the v-model array contents reflect the new values in the items? I can think of a way to do this programmatically, but I have lots of tables like this and hope there is an easier way, with the table props perhaps.
HTML:
<div id="app">
<v-app id="inspire">
<div>selected = {{ selected[0] }}</div>
<div>
<v-data-table
v-model="selected"
show-select
item-key="name"
:headers="headers"
:items="desserts"
:options.sync="options"
:server-items-length="totalDesserts"
:loading="loading"
class="elevation-1"
></v-data-table>
</div>
</v-app>
</div>
JS:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
selected: [],
totalDesserts: 0,
desserts: [],
loading: true,
options: {},
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: 'Time', value: 'time' },
],
reloadTimerId: Number,
}
},
watch: {
options: {
handler () {
this.getDataFromApi()
},
deep: true,
},
},
mounted () {
this.getDataFromApi();
this.reloadTimerId = setInterval(this.getDataFromApi, 5000);
},
methods: {
getDataFromApi () {
this.loading = true
this.fakeApiCall().then(data => {
this.desserts = data.items
this.totalDesserts = data.total
this.loading = false
})
},
/**
* In a real application this would be a call to fetch() or axios.get()
*/
fakeApiCall () {
return new Promise((resolve, reject) => {
const { sortBy, sortDesc, page, itemsPerPage } = this.options
let items = this.getDesserts()
const total = items.length
if (sortBy.length === 1 && sortDesc.length === 1) {
items = items.sort((a, b) => {
const sortA = a[sortBy[0]]
const sortB = b[sortBy[0]]
if (sortDesc[0]) {
if (sortA < sortB) return 1
if (sortA > sortB) return -1
return 0
} else {
if (sortA < sortB) return -1
if (sortA > sortB) return 1
return 0
}
})
}
if (itemsPerPage > 0) {
items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
}
setTimeout(() => {
resolve({
items,
total,
})
}, 1000)
})
},
getDesserts () {
return [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
time: new Date(),
},
{
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%',
},
]
},
},
})
I do not think there is any "build-in" way to do what you want. Problem is model (selected in your code) holds references of selected objects from items/deserts array. If you replace items/deserts (with this.desserts = data.items) with completely new array containing completely new objects, this is what you get...
So doing this yourself is most certainly only way. Either:
Recreate selected whenever you replace items/deserts
this.selected = data.items.filter(i => this.selected.findIndex(item => item.name === i.name) > -1)
Or do not replace array and it's items - update existing objects with new data instead
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>
I am using Vuetify 2 to create a data table for an app. In the data table I have custom headers, with slots, including "text", "value", "sortable". Is there a slot I can add to specify the font color and font size I want for each header? If I add a class parameter, how do I add the CSS specifics needed for the headers?
Example code I am using:
data: () => ({
dataFilters: {},
selectedRows: [],
gridConfig: {
records: [],
loading: true,
options: {
itemsPerPageOptions: [10, 25, 50, 100],
totalPages: 0,
itemsPerPage: 10,
page: 1,
descending: false,
},
headers: [
{
text: '__HEADER__MENU__',
value: `__HEADER__MENU__`,
sortable: false,
},
Thank you!
Yes it is possible to set custom color to vuetify data-table header and font size
You need to use class property in headers object
headers: [
{
text: '__HEADER__MENU__',
value: `__HEADER__MENU__`,
sortable: false,
class: "success--text title"
},
success--text class changes the color of your header
title increase the font size of you header, read all the fonts typography and colors in Vuetify
For dynamically setting the headers classes, use created hook to loop through this.headers and set the headers
Here is the working codepen:
https://codepen.io/chansv/pen/WNNGzwm?&editable=true&editors=101
<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>
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%',
},
],
}
},
})