Filtering for DataTable

pull/14/head
cagataycivici 2019-07-02 15:57:03 +03:00
parent ea8b67fda3
commit f7b2492c82
4 changed files with 195 additions and 0 deletions

View File

@ -49,6 +49,14 @@ export default {
footerClass: {
type: String,
default: null
},
filterMatchMode: {
type: String,
default: 'startsWith'
},
excludeGlobalFilter: {
type: Boolean,
default: false
}
},
render() {

View File

@ -21,6 +21,7 @@
<ColumnSlot :column="col" type="header" v-if="col.$scopedSlots.header" />
<span class="p-column-title" v-if="col.header">{{col.header}}</span>
<span v-if="col.sortable" :class="getSortableColumnIcon(col)"></span>
<ColumnSlot :column="col" type="filter" v-if="col.$scopedSlots.filter" />
</th>
</tr>
</thead>
@ -66,6 +67,7 @@
<script>
import ObjectUtils from '../utils/ObjectUtils';
import FilterUtils from '../utils/FilterUtils';
import DomHandler from '../utils/DomHandler';
import Paginator from '../paginator/Paginator';
@ -175,6 +177,10 @@ export default {
sortMode: {
type: String,
default: 'single'
},
filters: {
type: Object,
default: null
}
},
data() {
@ -369,6 +375,53 @@ export default {
this.d_multiSortMeta.push(meta);
this.d_multiSortMeta = [...this.d_multiSortMeta];
},
filter(data) {
let filteredValue = [];
for(let i = 0; i < data.length; i++) {
let localMatch = true;
let globalMatch = false;
for(let j = 0; j < this.columns.length; j++) {
let col = this.columns[j];
let columnField = col.field;
//local
if (this.filters.hasOwnProperty(columnField)) {
let filterValue = this.filters[columnField];
let dataFieldValue = ObjectUtils.resolveFieldData(data[i], columnField);
let filterConstraint = FilterUtils[col.filterMatchMode];
if (!filterConstraint(dataFieldValue, filterValue)) {
localMatch = false;
}
if (!localMatch) {
break;
}
}
if (!col.excludeGlobalFilter && this.hasGlobalFilter && !globalMatch) {
globalMatch = FilterUtils.contains(ObjectUtils.resolveFieldData(data[i], columnField), this.filters['global']);
}
}
let matches = localMatch;
if(this.hasGlobalFilter) {
matches = localMatch && globalMatch;
}
if(matches) {
filteredValue.push(data[i]);
}
}
if (filteredValue.length === data.length) {
filteredValue = data;
}
return filteredValue;
}
},
computed: {
@ -389,6 +442,10 @@ export default {
data = this.sortMultiple(data);
}
if (this.hasFilters) {
data = this.filter(data);
}
if (this.paginator) {
const first = this.lazy ? 0 : this.d_first;
return data.slice(first, first + this.d_rows);
@ -431,6 +488,12 @@ export default {
}
return hasFooter;
},
hasFilters() {
return this.filters && Object.keys(this.filters).length > 0 && this.filters.constructor === Object;
},
hasGlobalFilter() {
return this.filters && this.filters.hasOwnProperty('global');
}
},
components: {

View File

@ -126,6 +126,11 @@ export default new Router({
name: 'datatablesort',
component: () => import('./views/datatable/DataTableSortDemo.vue')
},
{
path: '/datatable/filter',
name: 'datatablefilter',
component: () => import('./views/datatable/DataTableFilterDemo.vue')
},
{
path: '/dataview',
name: 'dataview',

View File

@ -0,0 +1,119 @@
<template>
<div>
<DataTableSubMenu />
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable - Filter</h1>
<p>Filtering is enabled by defining a filter template per column to populate the filters property of the DataTable.</p>
</div>
</div>
<div class="content-section implementation">
<DataTable :value="cars" :filters="filters" :paginator="true" :rows="10">
<template #header>
<div style="text-align: right">
<i class="pi pi-search" style="margin: 4px 4px 0px 0px;"></i>
<InputText v-model="filters['global']" placeholder="Global Search" size="50" />
</div>
</template>
<Column field="vin" header="Vin" filterMatchMode="startsWith">
<template #filter>
<InputText type="text" v-model="filters['vin']" class="p-column-filter" />
</template>
</Column>
<Column field="year" header="Year" filterMatchMode="contains">
<template #filter>
<InputText type="text" v-model="filters['year']" class="p-column-filter" />
</template>
</Column>
<Column field="brand" header="Brand" filterMatchMode="equals">
<template #filter>
<Dropdown v-model="filters['brand']" :options="brands" optionLabel="brand" optionValue="value" placeholder="Select a Brand" class="p-column-filter">
<template #option="slotProps">
<div class="p-clearfix p-dropdown-car-option">
<img :alt="slotProps.option.brand" :src="'demo/images/car/' + slotProps.option.brand + '.png'" />
<span>{{slotProps.option.brand}}</span>
</div>
</template>
</Dropdown>
</template>
</Column>
<Column field="color" header="Color" filterMatchMode="in">
<template #filter>
<MultiSelect v-model="filters['color']" :options="colors" optionLabel="name" optionValue="value" placeholder="Select a Color" />
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script>
import CarService from '../../service/CarService';
import DataTableSubMenu from './DataTableSubMenu';
export default {
data() {
return {
filters: {},
brands: [
{brand: 'Audi', value: 'Audi'},
{brand: 'BMW', value: 'BMW'},
{brand: 'Fiat', value: 'Fiat'},
{brand: 'Honda', value: 'Honda'},
{brand: 'Jaguar', value: 'Jaguar'},
{brand: 'Mercedes', value: 'Mercedes'},
{brand: 'Renault', value: 'Renault'},
{brand: 'Volkswagen', value: 'Volkswagen'},
{brand: 'Volvo', value: 'Volvo'}
],
colors: [
{name: 'White', value: 'White'},
{name: 'Green', value: 'Green'},
{name: 'Silver', value: 'Silver'},
{name: 'Black', value: 'Black'},
{name: 'Red', value: 'Red'},
{name: 'Maroon', value: 'Maroon'},
{name: 'Brown', value: 'Brown'},
{name: 'Orange', value: 'Orange'},
{name: 'Blue', value: 'Blue'}
],
cars: null
}
},
carService: null,
created() {
this.carService = new CarService();
},
mounted() {
this.carService.getCarsLarge().then(data => this.cars = data);
},
components: {
'DataTableSubMenu': DataTableSubMenu
}
}
</script>
<style lang="scss" scoped>
/deep/ .p-dropdown-label {
text-align: left;
}
.p-multiselect {
width: 100%;
}
.p-dropdown-car-option {
img {
vertical-align: middle;
margin-right: .5em;
width: 24px;
}
span {
float: right;
margin-top: .125em;
}
}
</style>