Reputation: 2040
In a data table, I want to display only items, where the property 'display' is 'true'. There is the property 'filter' in the component v-data-table. But there is no example showing, how to use it.
I have tried several approaches, but without success. The following code snippet is also available at codepen.
new Vue({
el: '#app',
data () {
return {
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: [
{
value: false,
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
display: false
},
{
value: false,
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
display: true
},
{
value: false,
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
display: false
},
{
value: false,
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
display: true
},
{
value: false,
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
display: false
},
{
value: false,
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
display: true
},
{
value: false,
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
display: false
},
{
value: false,
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
display: false
},
{
value: false,
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
display: false
},
{
value: false,
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
display: false
}
]
}
},
methods: {
filterItems(val, search) {
return val.display;
}
}
})
<!DOCTYPE html>
<html>
<head>
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="desserts"
hide-actions
item-key="name"
:filter="filterItems"
>
<template slot="items" slot-scope="props">
<tr @click="props.expanded = !props.expanded" :class="[props.expanded && 'expanded']">
<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="text-xs-right">{{ props.item.iron }}</td>
</tr>
</template>
<template slot="expand" slot-scope="props">
<v-card flat>
<v-card-text>Peek-a-boo!</v-card-text>
</v-card>
</template>
</v-data-table>
</v-app>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify/dist/vuetify.js"></script>
</body>
</html>
The problematic part of the code is:
methods: {
filterItems(val, search) {
return ???;
}
}
Upvotes: 3
Views: 29117
Reputation: 11
Here is the solution I came up with. I was having a similar problem where I wanted to implement a custom filter that still worked with the search. I ended up using a computed property that applies a filter to the data and that computed property is what gets sent to the table.
computed: {
dataListDisplay: function() {
return this.applyFilters(this.dataList);
},
}
dataListDisplay is what you send to the v-data-table items prop. And you will need to implement the applFilters function how you'd like.
My table is read only. I imagine you'd have to be careful if you are changing the data. You may need to provide a setter for the dataListDisplay computed function.
Upvotes: 1
Reputation: 11
For props, filter, this should help:
methods: {
filterItems(val, search) {
return val != null && typeof val !== 'boolean' && val.toString().toLowerCase().indexOf(search) !== -1;
}
}
Upvotes: 0
Reputation: 383
I was struggling for a long time with this issue because I also thought :filter did not work. Later, after a lot of pain, I realised that I needed a :search prop to use :filter, and the functionality that I wanted was not the one that is provided by Vuetify.
Like you, I wanted to filter my data-table with a function that returned a boolean, i.e: true, if row should be displayed.
If someone is looking for a quick solution to do the same, a simple "v-if" should do the trick. Based on the example from above:
<template slot="items" slot-scope="props" v-if="props.item.display">
There are other solutions of course, depending on your needs, like using .filter method on the desserts array itself.
In my case, because I wanted to always display 5 rows at a time in my data-table (not using hide-actions), I ended up using the created() lifecycle hook, instead of a v-if:
created: function() {
this.shownDesserts = this.desserts.filter(dessert => {
return dessert.display
})
},
Upvotes: 4
Reputation: 50808
Looking at the source code, I think you really want custom-filter
as opposed to filter
:
(items: object[], search: string, filter: Filter): object[]
So you would define a function and pass it as an argument to the custom-filter
property on the table. When searching, you are provided with all the items in the table represented by an array of objects (object[]
), the search string that was typed into the search box, and the filter function to apply against all the objects in the array, so:
:custom-filter="filterItems"
filterItems(items, search, filter) {
items.filter(r => filter(r.calories > search))
}
The above of course is just a very rudimentary example.
Upvotes: 2