Make the content of the column align left in vue datatable - vue.js

I have a datatable in my vue component.
Following is my header array.
HeaderArray() {
return [
{text: 'Document', value: 'document',classList: 'w-1/3'},
{text: 'Added by', value: 'added_user_name',classList: 'w-1/3'},
{text: 'Expiration', value: 'valid_date'},
{text: 'Validity', value: 'validity_status',classList: 'w-1/3', align:'start'},
{text: '', value: 'actions'},
];
},
Cell content of the Validity column is centered, But I want them to be align left.
Eventhough I triedalign:'start' the content display center...
How to make them align left?
Column header is aligned to left though...

By default column data in vue-data-table is left aligned. Hence, all the columns are already left aligned but if you want to make other columns are center aligned and validity as left aligned then you have to apply align: 'center' property in all the other column headers object instead of changing for validity column.
Demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
headers: [
{text: 'Document', value: 'document',classList: 'w-1/3', align:'center'},
{text: 'Added by', value: 'added_user_name',classList: 'w-1/3', align:'center'},
{text: 'Expiration', value: 'valid_date', align:'center'},
{text: 'Validity', value: 'validity_status',classList: 'w-1/3'},
{text: 'Actions', value: 'actions', align:'center'},
],
documentDetails: [
{
document: 'Document 1',
added_user_name: 'user 1',
valid_date: '04-12-2022',
validity_status: 'valid',
actions: 'Edit'
},
{
document: 'Document 2',
added_user_name: 'user 2',
valid_date: '05-12-2022',
validity_status: 'invalid',
actions: 'Edit'
}
],
}
},
})
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.4/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.4/dist/vuetify.min.css"/>
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="documentDetails"
class="elevation-1"
></v-data-table>
</v-app>
</div>

Related

How can bind change of object data instantly in Vue.js?

<div
v-if="!item.editNickname"
#click="item.editNickname=true, item.tmpNickname=item.nickname"
>{{item.nickname}}</div>
<v-text-field
v-model="item.tmpNickname"
v-if="item.editNickname||!item.nickname"
outlined
dense
hide-details
single-line
v-on:keyup.enter="saveNickname(item)"
/>
Here is my code.
I want to edit nickname in data table.
If user click nickname(div), text field will show up.
But this code cannot bind instantly(Actually value is binded correct, but UI is not react).
Can I make UI react without other action?
=====================================================
+INFO
This code block is in 'v-data-table' which basic component of vuetify.
The item is an Object.
You can do as below, I'm thinking tmpNickname is not one of the property that you are binding to the data table. See below for the sample code.
You can find the working code here
Template Code:
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="desserts"
class="elevation-1"
>
<template v-slot:item.nickname="{ item }">
<div v-if="!item.editable" #click="item.editable = true; item['tmpnickname'] = item.nickname">{{ item.nickname }}</div>
<v-text-field
v-model="item['tmpnickname']"
v-if="item.editable"
outlined
dense
hide-details
single-line
v-on:keyup.enter="saveNickname(item)"
/>
</template>
</v-data-table>
</v-app>
</div>
Script Code:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
headers: [
{
text: 'Col 1',
value: 'name',
},
{ text: 'Nick name', value: 'nickname' }
],
desserts: [
{
name: 'Row 1',
nickname: 'Name 1',
editable: false
},
{
name: 'Row 2',
nickname: 'Name 2',
editable: false
},
{
name: 'Row 3',
nickname: 'Name 3',
editable: false
}
],
}
},
methods: {
saveNickname (item) {
item.editable = false;
item.nickname = item.tmpnickname;
}
},
})

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.

How can I disable literal values in Vuetify?

I am having problems when using the "item-disabled" prop on the v-select component from vuetify. I am trying to use this with literal options.
Here is the snippet which reproduces the issue:
In this example I would like to disable the option "Buzz".
Vue.use(Vuetify)
new Vue({
el: '#app',
data: () => ({
items: ['Foo', 'Bar', 'Fizz', 'Buzz'],
disabledItems: ['Buzz'],
})
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.5.14/vuetify.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.5.14/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container fluid grid-list-xl>
<v-layout wrap align-center>
<v-flex xs12 sm6 d-flex>
<v-select :items="items" :item-disabled="disabledItems" box label="Box style"></v-select>
</v-flex>
</v-layout>
</v-container>
</v-app>
</div>
<v-select :items="items" :item-disabled="disabledItems"></v-select>
...
items: ['Foo', 'Bar', 'Fizz', 'Buzz'],
disabledItems: ['Buzz'],
I do realize that I could use the non-literal key-value pair like in this example: https://codepen.io/anon/pen/joyoaj and it would work. But I would prefer to not have to write a wrapper component to convert literal options to key-value just to work around this.
<v-select :items="items"></v-select>
...
items: [
{text: 'Foo', value: 'Foo'},
{text: 'Bar', value: 'Bar'},
{text: 'Fizz', value: 'Fizz'},
{text: 'Buzz', value: 'Buzz', disabled: true},
],
Does anyone know how to get disabling literal values working?
You cant do it like that because item-disabled property is actually for something else.
From docs:
item-disabled
Default: disabled
Type: string | array | function
Set property of items's disabled value
So item-disabled just specifies which field on the objects will be treated as "disabled-field". By default, that field is disabled.
Without item-disabled you would have objects like this:
items: [
{text: 'Foo', value: 'Foo'},
{text: 'Buzz', value: 'Buzz', disabled: true},
],
And if objects have some other "disabled-property" (e.g. customDisabled) then use item-disabled prop like this:
<v-select :items="items" item-disabled="customDisabled"
// ...
items: [
{text: 'Foo', value: 'Foo'},
{text: 'Buzz', value: 'Buzz', customDisabled: true},
],
Codepen
If you need to preserve your arrays of strings then you could just map items to the array of objects and pass it:
<v-select :items="computedItems"
// ...
data: () => ({
items: ['Foo', 'Bar', 'Fizz', 'Buzz'],
disabledItems: ['Buzz'],
}),
computed: {
computedItems() {
return this.items.map(item => {
return {
text: item,
disabled: this.disabledItems.includes(item)
}
})
}
}
Codepen
Additionally, you can pass array to reach desired depth if your disabled field is nested, for example:
:item-disabled="['meta', 'disabled']"
// ...
{
text: item,
meta: {
disabled: true
}
}
Real working minimal example with function checking per item.
<v-select
:items="items"
item-text="name"
item-value="id"
:item-disabled="checkIsItemDisabled"
/>
<script>
data: function(){
return {
items: [
{id: 1, name: 'Foo'},
{id: 2, name: 'Bar'},
],
},
methods: {
checkIsItemDisabled(item) {
return (item.id === 1)
},
}
},
</script>
Adding the function option to #Traxo's answer:
<v-select :items="items" item-disabled="disableItem">
...
methods: {
disableItem(item) {
if (item.prop === this.anyOtherPropValue) {
return true;
}
return false;
},
},
Yes is reactive in case this.anyOtherPropValue change

Vuetify data tables search not working

Im new in Vue and Vuetify. I use vuetify data table in my project. Everything working fine except the Search options. I use everything as the documentation. But still not get any solution.
As the basic requirements I use these code to adding search
Template
<v-text-field
v-model="search"
append-icon="search"
label="Search"
single-line
hide-details
></v-text-field>
<v-data-table
:headers="headers"
:items="sales"
:search="search"
:rows-per-page-items="rowsPerPageItems"
row
wrap
class="elevation-1"
>
Script
data(){
return{
search: '',
}
}
Here is the complete code
https://github.com/Shakilzaman87/pukucrm/blob/master/src/components/sales/Sales.vue
Vuetify should warn you in the console about this:
[Vuetify] Headers must have a value property that corresponds to a
value in the v-model array in "v-data-table"
So you can fix the search option by adding values:
headers: [
{ text: 'Item Name', value: 'item_name' },
{ text: 'Unit Price', value: 'price' },
{ text: 'Quantity', value: 'quantity' },
{ text: 'Customer', value: 'customer' },
{ text: 'Created', value: 'timestamp' },
{ text: 'Total', value: 'total' },
{ text: 'Action', value: 'item_name' }
]
(data from your repo)

How do I use "custom filter" prop in data tables in vuetify? or How do I create a custom filter to filter by headers?

As of date of posting, I cannot find any documentation to use the "custom filter" prop in data tables.
I just want to create a custom filter to filter my data table by headers.
I have a dropdown, and when user click on one of the options for the dropdown, it will filter the list for one specific header.
Example:
Dropdown options:
Food type: fruit, meat, vegetable
Bakchoi (vegetable)
Pork (meat)
Chicken Thigh (meat)
watermelon (fruit)
If I select dropdown as meat, it should only show me pork and chicken thigh.
Looking at the code on Github1, it looks like the customFilter prop is used to overwrite the default method used to determine how the filter prop is applied to the items in the table.
The default customFilter method applies the filter function to each property name of each item object and filters out any items that don't include one property name that passes the filter:
customFilter: {
type: Function,
default: (items, search, filter) => {
search = search.toString().toLowerCase()
return items.filter(i => (
Object.keys(i).some(j => filter(i[j], search))
))
}
},
You might want to overwrite this function if you wanted to prevent any columns from being included in the filter or if there were specific rows that you always wanted to prevent from being filtered out.
You'll notice that the method also depends on the search prop, which must be a string.
All that said, you really don't need to use that prop for what you want to do. You should just make a computed property to filter the items based on your dropdown value and pass that computed property as the items prop.
Here's an example:
new Vue({
el: '#app',
data() {
return {
food: [
{ name: 'Bakchoi', type: 'vegetable', calories: 100 },
{ name: 'Pork', type: 'meat', calories: 200 },
{ name: 'Chicken Thigh', type: 'meat', calories: 300 },
{ name: 'Watermelon', type: 'fruit', calories: 10 },
],
headers: [
{ text: 'Name', align: 'left', value: 'name' },
{ text: 'Food Type', align: 'left', value: 'type' },
{ text: 'Calories', align: 'left', value: 'calories' },
],
foodType: null,
};
},
computed: {
filteredItems() {
return this.food.filter((i) => {
return !this.foodType || (i.type === this.foodType);
})
}
}
})
<script src="https://unpkg.com/vue#2.4.2/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#0.15.2/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#0.15.2/dist/vuetify.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons">
<div id="app">
<v-app>
<v-select
label="Food Type"
:items="['vegetable', 'meat', 'fruit']"
v-model="foodType"
></v-select>
<v-data-table
:headers="headers"
:items="filteredItems"
hide-actions
>
<template slot="items" scope="{ item }">
<td>{{ item.name }}</td>
<td>{{ item.type }}</td>
<td>{{ item.calories }}</td>
</template>
</v-data-table>
</v-app>
</div>
This answer was written when Vuetify was at v0.15.2. The source code for the VDataTable component at that version can be found here.
You can also go the customFilter approach like this, I've restricted the search to the type field.
new Vue({
el: '#app',
data() {
return {
food: [
{ name: 'Bakchoi', type: 'vegetable', calories: 100 },
{ name: 'Pork', type: 'meat', calories: 200 },
{ name: 'Chicken Thigh', type: 'meat', calories: 300 },
{ name: 'Watermelon', type: 'fruit', calories: 10 },
],
headers: [
{ text: 'Name', align: 'left', value: 'name' },
{ text: 'Food Type', align: 'left', value: 'type' },
{ text: 'Calories', align: 'left', value: 'calories' },
],
search: '',
};
},
methods: {
customFilter(items, search, filter) {
search = search.toString().toLowerCase()
return items.filter(row => filter(row["type"], search));
}
}
})
<script src="https://unpkg.com/vue#2.4.2/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#0.15.2/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#0.15.2/dist/vuetify.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons">
<div id="app">
<v-app>
<v-select
label="Food Type"
:items="['vegetable', 'meat', 'fruit']"
v-model="search"
></v-select>
<v-data-table
:headers="headers"
:items="food"
:search="search"
:custom-filter="customFilter"
hide-actions
>
<template slot="items" scope="{ item }">
<td>{{ item.name }}</td>
<td>{{ item.type }}</td>
<td>{{ item.calories }}</td>
</template>
</v-data-table>
</v-app>
</div>
In my case I have 2 different way of filtering which are search bar and drop down. I tried to use custom-filter for both of them, but it doesn't work, so I came up with another approach
<v-text-field v-model="search" label="Label"></v-text-field>
<v-select
v-model="select"
:items="food"
item-text="type"
item-value="type"
:label="Types"
#change="filterFoodUsingDropDown"
>
</v-select>
<v-data-table
:search="search"
:headers="headers"
:items="food"
:custom-filter="filterFoodUsingSearchbar"
>
data() {
return {
food: [
{ name: 'Bakchoi', type: 'vegetable', calories: 100 },
{ name: 'Pork', type: 'meat', calories: 200 },
{ name: 'Chicken Thigh', type: 'meat', calories: 300 },
{ name: 'Watermelon', type: 'fruit', calories: 10 },
],
headers: [
{ text: 'Name', align: 'left', value: 'name' },
{ text: 'Food Type', align: 'left', value: 'type' },
{ text: 'Calories', align: 'left', value: 'calories' },
],
search: '',
select: '',
};
},
methods: {
filterFoodUsingSearchbar(items, search, filter) {
// Condition
}
filterFoodUsingDropDown() {
if (this.select !== '') {
// In this case I use vuex to store the original data of the
food so that all the data is still exist even we filtered it out
this.food = this.$store.state.food.filter((item) => item.type === this.select)
}
}