Initiated Phase 2 of Advanced Table Filtering - Filter Menu feature
parent
716ff58bde
commit
a981d5504b
|
@ -117,10 +117,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-column-filter {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.country-item {
|
.country-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
import FilterMatchMode from './FilterMatchMode';
|
import FilterMatchMode from './FilterMatchMode';
|
||||||
|
import FilterOperator from './FilterOperator';
|
||||||
|
|
||||||
export {FilterMatchMode};
|
export {FilterMatchMode,FilterOperator};
|
|
@ -62,10 +62,6 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
filterOperator: {
|
|
||||||
type: String,
|
|
||||||
default: 'and'
|
|
||||||
},
|
|
||||||
showFilterOperator: {
|
showFilterOperator: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
|
|
@ -17,8 +17,25 @@
|
||||||
<li class="p-column-filter-row-item" @click="onRowClearItemClick()" @keydown="onRowMatchModeKeyDown($event)" @keydown.enter="onRowClearItemClick()">{{noFilterLabel}}</li>
|
<li class="p-column-filter-row-item" @click="onRowClearItemClick()" @keydown="onRowMatchModeKeyDown($event)" @keydown.enter="onRowClearItemClick()">{{noFilterLabel}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
<template>
|
<template v-else>
|
||||||
<div>TODO - Phase 2 Menu</div>
|
<div class="p-column-filter-operator" v-if="isShowOperator">
|
||||||
|
<CFDropdown :options="operatorOptions" :modelValue="operator" @update:modelValue="onOperatorChange($event)" class="p-column-filter-operator-dropdown" optionLabel="label" optionValue="value"></CFDropdown>
|
||||||
|
</div>
|
||||||
|
<div class="p-column-filter-constraints">
|
||||||
|
<div v-for="(fieldConstraint,i) of fieldConstraints" :key="fieldConstraint.matchMode + i" class="p-column-filter-constraint">
|
||||||
|
<CFDropdown v-if="showMatchModes && matchModes" :options="matchModes" :modelValue="fieldConstraint.matchMode" optionLabel="label" optionValue="value"
|
||||||
|
@update:modelValue="onMenuMatchModeChange($event, i)" class="p-column-filter-matchmode-dropdown"></CFDropdown>
|
||||||
|
<component v-if="display === 'menu'" :is="filterElement" :field="field" />
|
||||||
|
<CFButton v-if="showRemoveIcon" type="button" icon="pi pi-trash" class="p-column-filter-remove-button p-button-text p-button-danger p-button-sm" @click="removeConstraint(fieldConstraint)" :label="removeRuleButtonLabel"></CFButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-column-filter-add-rule" v-if="isShowAddConstraint">
|
||||||
|
<CFButton type="button" :label="addRuleButtonLabel" icon="pi pi-plus" class="p-column-filter-add-button p-button-text p-button-sm" @click="addConstraint()"></CFButton>
|
||||||
|
</div>
|
||||||
|
<div class="p-column-filter-buttonbar">
|
||||||
|
<CFButton type="button" class="p-button-outlined p-button-sm" @click="clearFilter()" :label="clearButtonLabel"></CFButton>
|
||||||
|
<CFButton type="button" class="p-button-sm" @click="applyFilter()" :label="applyButtonLabel"></CFButton>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<component :is="filterFooter" :field="field" />
|
<component :is="filterFooter" :field="field" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,6 +45,9 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {DomHandler,ConnectedOverlayScrollHandler} from 'primevue/utils';
|
import {DomHandler,ConnectedOverlayScrollHandler} from 'primevue/utils';
|
||||||
|
import {FilterOperator} from 'primevue/api';
|
||||||
|
import Dropdown from 'primevue/dropdown';
|
||||||
|
import Button from 'primevue/button';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
emits: ['filtermeta-change'],
|
emits: ['filtermeta-change'],
|
||||||
|
@ -52,10 +72,6 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
operator: {
|
|
||||||
type: String,
|
|
||||||
default: 'and'
|
|
||||||
},
|
|
||||||
showOperator: {
|
showOperator: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
@ -81,8 +97,8 @@ export default {
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
maxConstraints: {
|
maxConstraints: {
|
||||||
type: Boolean,
|
type: Number,
|
||||||
default: true
|
default: 2
|
||||||
},
|
},
|
||||||
filterElement: null,
|
filterElement: null,
|
||||||
filterHeader: null,
|
filterHeader: null,
|
||||||
|
@ -95,7 +111,8 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
overlayVisible: false,
|
overlayVisible: false,
|
||||||
defaultMatchMode: null
|
defaultMatchMode: null,
|
||||||
|
defaultOperator: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
overlay: null,
|
overlay: null,
|
||||||
|
@ -107,7 +124,13 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.filters && this.filters[this.field]) {
|
if (this.filters && this.filters[this.field]) {
|
||||||
this.defaultMatchMode = this.filters[this.field].matchMode;
|
if (this.display === 'row') {
|
||||||
|
this.defaultMatchMode = this.filters[this.field].matchMode;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.defaultMatchMode = this.filters[this.field][0].matchMode;
|
||||||
|
this.defaultOperator = this.filters[this.field][0].operator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -118,11 +141,16 @@ export default {
|
||||||
_filters[this.field].matchMode = this.defaultMatchMode;
|
_filters[this.field].matchMode = this.defaultMatchMode;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_filters[this.field] = {value: null, matchMode: this.defaultMatchMode, operator: this.operator};
|
_filters[this.field] = {value: null, matchMode: this.defaultMatchMode, operator: this.defaultOperator};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit('filtermeta-change', _filters);
|
this.$emit('filtermeta-change', _filters);
|
||||||
},
|
},
|
||||||
|
applyFilter() {
|
||||||
|
let _filters = {...this.filters};
|
||||||
|
this.$emit('filtermeta-change', _filters);
|
||||||
|
this.hide();
|
||||||
|
},
|
||||||
hasFilter() {
|
hasFilter() {
|
||||||
let fieldFilter = this.filters[this.field];
|
let fieldFilter = this.filters[this.field];
|
||||||
if (fieldFilter) {
|
if (fieldFilter) {
|
||||||
|
@ -309,6 +337,34 @@ export default {
|
||||||
window.removeEventListener('resize', this.resizeListener);
|
window.removeEventListener('resize', this.resizeListener);
|
||||||
this.resizeListener = null;
|
this.resizeListener = null;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onOperatorChange(value) {
|
||||||
|
let _filters = {...this.filters};
|
||||||
|
_filters[this.field].forEach(filterMeta => {
|
||||||
|
filterMeta.operator = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.showApplyButton) {
|
||||||
|
this.$emit('filtermeta-change', _filters);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMenuMatchModeChange(value, index) {
|
||||||
|
let _filters = {...this.filters};
|
||||||
|
_filters[this.field][index].matchMode = value;
|
||||||
|
|
||||||
|
if (!this.showApplyButton) {
|
||||||
|
this.$emit('filtermeta-change', _filters);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addConstraint() {
|
||||||
|
let _filters = {...this.filters};
|
||||||
|
_filters[this.field].push({value: null, matchMode: this.defaultMatchMode()});
|
||||||
|
this.$emit('filtermeta-change', _filters);
|
||||||
|
},
|
||||||
|
removeConstraint(filterMeta) {
|
||||||
|
let _filters = {...this.filters};
|
||||||
|
_filters[this.field] = _filters[this.field].filter(meta => meta !== filterMeta);
|
||||||
|
this.$emit('filtermeta-change', _filters);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -332,10 +388,46 @@ export default {
|
||||||
return {label: this.$primevue.config.locale[key], value: key}
|
return {label: this.$primevue.config.locale[key], value: key}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
operatorOptions() {
|
||||||
|
return [
|
||||||
|
{label: this.$primevue.config.locale.matchAll, value: FilterOperator.AND},
|
||||||
|
{label: this.$primevue.config.locale.matchAny, value: FilterOperator.OR}
|
||||||
|
];
|
||||||
|
},
|
||||||
noFilterLabel() {
|
noFilterLabel() {
|
||||||
return this.$primevue.config.locale.noFilter;
|
return this.$primevue.config.locale.noFilter;
|
||||||
|
},
|
||||||
|
isShowOperator() {
|
||||||
|
return this.showOperator && this.type !== 'boolean';
|
||||||
|
},
|
||||||
|
operator() {
|
||||||
|
return this.filters[this.field][0].operator;
|
||||||
|
},
|
||||||
|
fieldConstraints() {
|
||||||
|
return this.filters[this.field];
|
||||||
|
},
|
||||||
|
showRemoveIcon() {
|
||||||
|
return this.fieldConstraints.length > 1;
|
||||||
|
},
|
||||||
|
removeRuleButtonLabel() {
|
||||||
|
return this.$primevue.config.locale.removeRule;
|
||||||
|
},
|
||||||
|
addRuleButtonLabel() {
|
||||||
|
return this.$primevue.config.locale.addRule;
|
||||||
|
},
|
||||||
|
isShowAddConstraint() {
|
||||||
|
return this.showAddButton && this.type !== 'boolean' && (this.fieldConstraints && this.fieldConstraints.length < this.maxConstraints);
|
||||||
|
},
|
||||||
|
clearButtonLabel() {
|
||||||
|
return this.$primevue.config.locale.clear;
|
||||||
|
},
|
||||||
|
applyButtonLabel() {
|
||||||
|
return this.$primevue.config.locale.apply;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
'CFDropdown': Dropdown,
|
||||||
|
'CFButton': Button
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -14,6 +14,11 @@
|
||||||
<span v-if="columnProp(col, 'sortable')" :class="getSortableColumnIcon(col)"></span>
|
<span v-if="columnProp(col, 'sortable')" :class="getSortableColumnIcon(col)"></span>
|
||||||
<span v-if="isMultiSorted(col)" class="p-sortable-column-badge">{{getMultiSortMetaIndex(col) + 1}}</span>
|
<span v-if="isMultiSorted(col)" class="p-sortable-column-badge">{{getMultiSortMetaIndex(col) + 1}}</span>
|
||||||
<DTHeaderCheckbox :checked="allRowsSelected" @change="onHeaderCheckboxChange($event)" :disabled="empty" v-if="columnProp(col, 'selectionMode') ==='multiple' && filterDisplay !== 'row'" />
|
<DTHeaderCheckbox :checked="allRowsSelected" @change="onHeaderCheckboxChange($event)" :disabled="empty" v-if="columnProp(col, 'selectionMode') ==='multiple' && filterDisplay !== 'row'" />
|
||||||
|
<DTColumnFilter v-if="filterDisplay === 'menu' && filters && filters[columnProp(col, 'filterField')||columnProp(col, 'field')]" :field="columnProp(col, 'filterField')||columnProp(col, 'field')" :type="columnProp(col, 'dataType')" display="menu"
|
||||||
|
:showMenu="columnProp(col, 'showFilterMenu')" :filterElement="col.children && col.children.filter" :filterHeader="col.children && col.children.filterHeader" :filterFooter="col.children && col.children.filterFooter"
|
||||||
|
:filters="filters" @filtermeta-change="$emit('filtermeta-change', $event)"
|
||||||
|
:showOperator="columnProp(col, 'showFilterOperator')" :showClearButton="columnProp(col, 'showClearButton')" :showApplyButton="columnProp(col, 'showApplyButton')"
|
||||||
|
:showMatchModes="columnProp(col, 'showFilterMatchModes')" :showAddButton="columnProp(col, 'showAddButton')" :matchModeOptions="columnProp(col, 'filterMatchModeOptions')" :maxConstraints="columnProp(col, 'maxConstraints')" />
|
||||||
</th>
|
</th>
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -21,11 +26,11 @@
|
||||||
<template v-for="(col,i) of columns">
|
<template v-for="(col,i) of columns">
|
||||||
<th v-if="rowGroupMode !== 'subheader' || (groupRowsBy !== columnProp(col, 'field'))" :key="columnProp(col, 'columnKey')||columnProp(col, 'field')||i"
|
<th v-if="rowGroupMode !== 'subheader' || (groupRowsBy !== columnProp(col, 'field'))" :key="columnProp(col, 'columnKey')||columnProp(col, 'field')||i"
|
||||||
:class="getFilterColumnHeaderClass(col)" :style="columnProp(col, 'filterHeaderStyle')">
|
:class="getFilterColumnHeaderClass(col)" :style="columnProp(col, 'filterHeaderStyle')">
|
||||||
<DTColumnFilter v-if="filters[columnProp(col, 'filterField')||columnProp(col, 'field')]" :field="columnProp(col, 'filterField')||columnProp(col, 'field')" :type="columnProp(col, 'dataType')" display="row"
|
<DTColumnFilter v-if="filters && filters[columnProp(col, 'filterField')||columnProp(col, 'field')]" :field="columnProp(col, 'filterField')||columnProp(col, 'field')" :type="columnProp(col, 'dataType')" display="row"
|
||||||
:showMenu="columnProp(col, 'showFilterMenu')" :filterElement="col.children && col.children.filter" :filterHeader="col.children && col.children.filterHeader" :filterFooter="col.children && col.children.filterFooter"
|
:showMenu="columnProp(col, 'showFilterMenu')" :filterElement="col.children && col.children.filter" :filterHeader="col.children && col.children.filterHeader" :filterFooter="col.children && col.children.filterFooter"
|
||||||
:filters="filters" @filtermeta-change="$emit('filtermeta-change', $event)"
|
:filters="filters" @filtermeta-change="$emit('filtermeta-change', $event)"
|
||||||
:operator="columnProp(col, 'filterOperator')" :showFilterOperator="columnProp(col, 'showFilterOperator')" :showClearButton="columnProp(col, 'showClearButton')" :showApplyButton="columnProp(col, 'showApplyButton')"
|
:showOperator="columnProp(col, 'showFilterOperator')" :showClearButton="columnProp(col, 'showClearButton')" :showApplyButton="columnProp(col, 'showApplyButton')"
|
||||||
:showFilterMatchModes="columnProp(col, 'showFilterMatchModes')" :showAddButton="columnProp(col, 'showAddButton')" :matchModeOptions="columnProp(col, 'filterMatchModeOptions')" :maxConstraints="columnProp(col, 'maxConstraints')" />
|
:showMatchModes="columnProp(col, 'showFilterMatchModes')" :showAddButton="columnProp(col, 'showAddButton')" :matchModeOptions="columnProp(col, 'filterMatchModeOptions')" :maxConstraints="columnProp(col, 'maxConstraints')" />
|
||||||
<DTHeaderCheckbox :checked="allRowsSelected" @change="onHeaderCheckboxChange($event)" :disabled="empty" v-if="columnProp(col, 'selectionMode')==='multiple'" />
|
<DTHeaderCheckbox :checked="allRowsSelected" @change="onHeaderCheckboxChange($event)" :disabled="empty" v-if="columnProp(col, 'selectionMode')==='multiple'" />
|
||||||
</th>
|
</th>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -182,7 +182,18 @@ export default class FilterUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
static is(value, filter, filterLocale) {
|
static is(value, filter, filterLocale) {
|
||||||
return this.filters.equals(value, filter, filterLocale);
|
if (filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === undefined || value === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.getTime && filter.getTime)
|
||||||
|
return value.getTime() === filter.getTime();
|
||||||
|
else
|
||||||
|
return ObjectUtils.removeAccents(value.toString()).toLocaleLowerCase(filterLocale) == ObjectUtils.removeAccents(filter.toString()).toLocaleLowerCase(filterLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
static isNot(value, filter, filterLocale) {
|
static isNot(value, filter, filterLocale) {
|
||||||
|
|
|
@ -2,22 +2,22 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="content-section introduction">
|
<div class="content-section introduction">
|
||||||
<div class="feature-intro">
|
<div class="feature-intro">
|
||||||
<h1>DataTable - Filter</h1>
|
<h1>DataTable <span>Filter</span></h1>
|
||||||
<p>Filtering is enabled by defining a filter template per column to populate the filters property of the DataTable.</p>
|
<p>Filtering feature provides advanced and flexible options to query the data.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content-section implementation">
|
<div class="content-section implementation">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5>Filter Row</h5>
|
<h5>Filter Menu</h5>
|
||||||
<p>Filters are displayed inline within a separate row.</p>
|
<p>Filters are displayed in an overlay..</p>
|
||||||
<DataTable :value="customers" :paginator="true" class="p-datatable-customers" :rows="10"
|
<DataTable :value="customers1" :paginator="true" class="p-datatable-customers p-datatable-gridlines" :rows="10"
|
||||||
dataKey="id" :filters="filters" filterDisplay="row" :loading="loading">
|
dataKey="id" :filters="filters1" filterDisplay="menu" :loading="loading1">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="p-d-flex p-jc-end">
|
<div class="p-d-flex p-jc-end">
|
||||||
<span class="p-input-icon-left ">
|
<span class="p-input-icon-left ">
|
||||||
<i class="pi pi-search" />
|
<i class="pi pi-search" />
|
||||||
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
|
<InputText v-model="filters1['global'].value" placeholder="Keyword Search" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,27 +33,28 @@
|
||||||
{{slotProps.data.name}}
|
{{slotProps.data.name}}
|
||||||
</template>
|
</template>
|
||||||
<template #filter>
|
<template #filter>
|
||||||
<InputText type="text" v-model="filters['name'].value" class="p-column-filter" placeholder="Search by name"/>
|
<InputText type="text" v-model="filters1['name'].value" class="p-column-filter" placeholder="Search by name"/>
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column header="Country" filterField="country.name" filterMatchMode="contains">
|
<Column header="Country" filterField="country.name">
|
||||||
<template #body="slotProps">
|
<template #body="slotProps">
|
||||||
<span class="p-column-title">Country</span>
|
<span class="p-column-title">Country</span>
|
||||||
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
|
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
|
||||||
<span class="image-text">{{slotProps.data.country.name}}</span>
|
<span class="image-text">{{slotProps.data.country.name}}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #filter>
|
<template #filter>
|
||||||
<InputText type="text" v-model="filters['country.name'].value" class="p-column-filter" placeholder="Search by country"/>
|
<InputText type="text" v-model="filters1['country.name'].value" class="p-column-filter" placeholder="Search by country"/>
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column header="Agent" filterField="representative" filterMatchMode="in" :showFilterMenu="false">
|
<Column header="Agent" filterField="representative" :showFilterMatchModes="false" :showFilterOperator="false" :showAddButton="false">
|
||||||
<template #body="slotProps">
|
<template #body="slotProps">
|
||||||
<span class="p-column-title">Agent</span>
|
<span class="p-column-title">Agent</span>
|
||||||
<img :alt="slotProps.data.representative.name" :src="'demo/images/avatar/' + slotProps.data.representative.image" width="32" style="vertical-align: middle" />
|
<img :alt="slotProps.data.representative.name" :src="'demo/images/avatar/' + slotProps.data.representative.image" width="32" style="vertical-align: middle" />
|
||||||
<span class="image-text">{{slotProps.data.representative.name}}</span>
|
<span class="image-text">{{slotProps.data.representative.name}}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #filter>
|
<template #filter>
|
||||||
<MultiSelect v-model="filters['representative'].value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
|
<div class="p-mb-3 p-text-bold">Agent Picker</div>
|
||||||
|
<MultiSelect v-model="filters1['representative'].value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
|
||||||
<template #option="slotProps">
|
<template #option="slotProps">
|
||||||
<div class="p-multiselect-representative-option">
|
<div class="p-multiselect-representative-option">
|
||||||
<img :alt="slotProps.option.name" :src="'demo/images/avatar/' + slotProps.option.image" width="32" style="vertical-align: middle" />
|
<img :alt="slotProps.option.name" :src="'demo/images/avatar/' + slotProps.option.image" width="32" style="vertical-align: middle" />
|
||||||
|
@ -63,26 +64,137 @@
|
||||||
</MultiSelect>
|
</MultiSelect>
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column field="status" header="Status" filterMatchMode="equals" :showFilterMenu="false">
|
<Column header="Date" filterField="date" dataType="date">
|
||||||
|
<template #body="slotProps">
|
||||||
|
<span class="p-column-title">Date</span>
|
||||||
|
{{slotProps.data.date}}
|
||||||
|
</template>
|
||||||
|
<template #filter>
|
||||||
|
<Calendar v-model="filters1['date'].value" dateFormat="mm/dd/yy" />
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column header="Balance" filterField="balance" dataType="numeric">
|
||||||
|
<template #body="slotProps">
|
||||||
|
<span class="p-column-title">Balance</span>
|
||||||
|
{{formatCurrency(slotProps.data.balance)}}
|
||||||
|
</template>
|
||||||
|
<template #filter>
|
||||||
|
<InputNumber v-model="filters1['balance'].value" mode="currency" currency="USD" locale="en-US" />
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column field="status" header="Status">
|
||||||
<template #body="slotProps">
|
<template #body="slotProps">
|
||||||
<span class="p-column-title">Status</span>
|
<span class="p-column-title">Status</span>
|
||||||
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
|
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #filter>
|
<template #filter>
|
||||||
<Dropdown v-model="filters['status'].value" :options="statuses" placeholder="Any" class="p-column-filter" :showClear="true">
|
<Dropdown v-model="filters1['status'].value" :options="statuses" placeholder="Any" class="p-column-filter" :showClear="true">
|
||||||
<template #option="slotProps">
|
<template #option="slotProps">
|
||||||
<span :class="'customer-badge status-' + slotProps.option">{{slotProps.option}}</span>
|
<span :class="'customer-badge status-' + slotProps.option">{{slotProps.option}}</span>
|
||||||
</template>
|
</template>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column field="verified" header="Verified" filterMatchMode="equals" dataType="boolean" headerStyle="width: 6rem">
|
<Column field="activity" header="Activity" :showFilterMatchModes="false" :showFilterOperator="false" :showAddButton="false">
|
||||||
|
<template #body="slotProps">
|
||||||
|
<span class="p-column-title">Status</span>
|
||||||
|
<ProgressBar :value="slotProps.data.activity" :showValue="false"></ProgressBar>
|
||||||
|
</template>
|
||||||
|
<template #filter>
|
||||||
|
<Slider v-model="filters1['activity'][0].value" range class="p-m-3"></Slider>
|
||||||
|
<div class="p-d-flex p-ai-center p-jc-between p-px-2">
|
||||||
|
<span>{{filters1['activity'][0].value[0]}}</span>
|
||||||
|
<span>{{filters1['activity'][0].value[1]}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column field="verified" header="Verified" dataType="boolean" headerStyle="width: 8rem" :showFilterMatchModes="false" :showFilterOperator="false" :showAddButton="false">
|
||||||
<template #body="slotProps">
|
<template #body="slotProps">
|
||||||
<span class="p-column-title">Verified</span>
|
<span class="p-column-title">Verified</span>
|
||||||
<i class="pi" :class="{'true-icon pi-check-circle': slotProps.data.verified, 'false-icon pi-times-circle': !slotProps.data.verified}"></i>
|
<i class="pi" :class="{'true-icon pi-check-circle': slotProps.data.verified, 'false-icon pi-times-circle': !slotProps.data.verified}"></i>
|
||||||
</template>
|
</template>
|
||||||
<template #filter>
|
<template #filter>
|
||||||
<TriStateCheckbox v-model="filters['verified'].value" />
|
<TriStateCheckbox v-model="filters1['verified'].value" />
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<h5>Filter Row</h5>
|
||||||
|
<p>Filters are displayed inline within a separate row.</p>
|
||||||
|
<DataTable :value="customers2" :paginator="true" class="p-datatable-customers" :rows="10"
|
||||||
|
dataKey="id" :filters="filters2" filterDisplay="row" :loading="loading2">
|
||||||
|
<template #header>
|
||||||
|
<div class="p-d-flex p-jc-end">
|
||||||
|
<span class="p-input-icon-left ">
|
||||||
|
<i class="pi pi-search" />
|
||||||
|
<InputText v-model="filters2['global'].value" placeholder="Keyword Search" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #empty>
|
||||||
|
No customers found.
|
||||||
|
</template>
|
||||||
|
<template #loading>
|
||||||
|
Loading customers data. Please wait.
|
||||||
|
</template>
|
||||||
|
<Column field="name" header="Name">
|
||||||
|
<template #body="slotProps">
|
||||||
|
<span class="p-column-title">Name</span>
|
||||||
|
{{slotProps.data.name}}
|
||||||
|
</template>
|
||||||
|
<template #filter>
|
||||||
|
<InputText type="text" v-model="filters2['name'].value" class="p-column-filter" placeholder="Search by name"/>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column header="Country" filterField="country.name">
|
||||||
|
<template #body="slotProps">
|
||||||
|
<span class="p-column-title">Country</span>
|
||||||
|
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
|
||||||
|
<span class="image-text">{{slotProps.data.country.name}}</span>
|
||||||
|
</template>
|
||||||
|
<template #filter>
|
||||||
|
<InputText type="text" v-model="filters2['country.name'].value" class="p-column-filter" placeholder="Search by country"/>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column header="Agent" filterField="representative" :showFilterMenu="false">
|
||||||
|
<template #body="slotProps">
|
||||||
|
<span class="p-column-title">Agent</span>
|
||||||
|
<img :alt="slotProps.data.representative.name" :src="'demo/images/avatar/' + slotProps.data.representative.image" width="32" style="vertical-align: middle" />
|
||||||
|
<span class="image-text">{{slotProps.data.representative.name}}</span>
|
||||||
|
</template>
|
||||||
|
<template #filter>
|
||||||
|
<MultiSelect v-model="filters2['representative'].value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
|
||||||
|
<template #option="slotProps">
|
||||||
|
<div class="p-multiselect-representative-option">
|
||||||
|
<img :alt="slotProps.option.name" :src="'demo/images/avatar/' + slotProps.option.image" width="32" style="vertical-align: middle" />
|
||||||
|
<span class="image-text">{{slotProps.option.name}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MultiSelect>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column field="status" header="Status" :showFilterMenu="false">
|
||||||
|
<template #body="slotProps">
|
||||||
|
<span class="p-column-title">Status</span>
|
||||||
|
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
|
||||||
|
</template>
|
||||||
|
<template #filter>
|
||||||
|
<Dropdown v-model="filters2['status'].value" :options="statuses" placeholder="Any" class="p-column-filter" :showClear="true">
|
||||||
|
<template #option="slotProps">
|
||||||
|
<span :class="'customer-badge status-' + slotProps.option">{{slotProps.option}}</span>
|
||||||
|
</template>
|
||||||
|
</Dropdown>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column field="verified" header="Verified" dataType="boolean" headerStyle="width: 6rem">
|
||||||
|
<template #body="slotProps">
|
||||||
|
<span class="p-column-title">Verified</span>
|
||||||
|
<i class="pi" :class="{'true-icon pi-check-circle': slotProps.data.verified, 'false-icon pi-times-circle': !slotProps.data.verified}"></i>
|
||||||
|
</template>
|
||||||
|
<template #filter>
|
||||||
|
<TriStateCheckbox v-model="filters2['verified'].value" />
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
|
@ -108,13 +220,25 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CustomerService from '../../service/CustomerService';
|
import CustomerService from '../../service/CustomerService';
|
||||||
import {FilterMatchMode} from 'primevue/api';
|
import {FilterMatchMode,FilterOperator} from 'primevue/api';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
customers: null,
|
customers1: null,
|
||||||
filters: {
|
customers2: null,
|
||||||
|
filters1: {
|
||||||
|
'global': {value: null, matchMode: FilterMatchMode.CONTAINS},
|
||||||
|
'name': [{value: null, matchMode: FilterMatchMode.STARTS_WITH, operator: FilterOperator.AND}],
|
||||||
|
'country.name': [{value: null, matchMode: FilterMatchMode.STARTS_WITH, operator: FilterOperator.AND}],
|
||||||
|
'representative': [{value: null, matchMode: FilterMatchMode.IN}],
|
||||||
|
'date': [{value: null, matchMode: FilterMatchMode.IS, operator: FilterOperator.AND}],
|
||||||
|
'balance': [{value: null, matchMode: FilterMatchMode.EQUALS, operator: FilterOperator.AND}],
|
||||||
|
'status': [{value: null, matchMode: FilterMatchMode.EQUALS, operator: FilterOperator.AND}],
|
||||||
|
'activity': [{value: [0,100], matchMode: FilterMatchMode.BETWEEN}],
|
||||||
|
'verified': [{value: null, matchMode: FilterMatchMode.EQUALS, operator: FilterOperator.AND}]
|
||||||
|
},
|
||||||
|
filters2: {
|
||||||
'global': {value: null, matchMode: FilterMatchMode.CONTAINS},
|
'global': {value: null, matchMode: FilterMatchMode.CONTAINS},
|
||||||
'name': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
|
'name': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
|
||||||
'country.name': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
|
'country.name': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
|
||||||
|
@ -122,7 +246,6 @@ export default {
|
||||||
'status': {value: null, matchMode: FilterMatchMode.EQUALS},
|
'status': {value: null, matchMode: FilterMatchMode.EQUALS},
|
||||||
'verified': {value: null, matchMode: FilterMatchMode.EQUALS}
|
'verified': {value: null, matchMode: FilterMatchMode.EQUALS}
|
||||||
},
|
},
|
||||||
loading: true,
|
|
||||||
representatives: [
|
representatives: [
|
||||||
{name: "Amy Elsner", image: 'amyelsner.png'},
|
{name: "Amy Elsner", image: 'amyelsner.png'},
|
||||||
{name: "Anna Fali", image: 'annafali.png'},
|
{name: "Anna Fali", image: 'annafali.png'},
|
||||||
|
@ -138,40 +261,20 @@ export default {
|
||||||
statuses: [
|
statuses: [
|
||||||
'unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal'
|
'unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal'
|
||||||
],
|
],
|
||||||
|
loading1: true,
|
||||||
|
loading2: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.customerService = new CustomerService();
|
this.customerService = new CustomerService();
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.customerService.getCustomersLarge().then(data => this.customers = data);
|
this.customerService.getCustomersLarge().then(data => {this.customers1 = data; this.loading1 = false;});
|
||||||
this.loading = false;
|
this.customerService.getCustomersLarge().then(data => {this.customers2 = data; this.loading2 = false;});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
filterDate(value, filter) {
|
formatCurrency(value) {
|
||||||
if (filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) {
|
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value === this.formatDate(filter);
|
|
||||||
},
|
|
||||||
formatDate(date) {
|
|
||||||
let month = date.getMonth() + 1;
|
|
||||||
let day = date.getDate();
|
|
||||||
|
|
||||||
if (month < 10) {
|
|
||||||
month = '0' + month;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (day < 10) {
|
|
||||||
day = '0' + day;
|
|
||||||
}
|
|
||||||
|
|
||||||
return date.getFullYear() + '-' + month + '-' + day;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -527,10 +527,6 @@ input[type="number"]::-webkit-inner-spin-button {
|
||||||
margin-top: .125rem;
|
margin-top: .125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-column-filter {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.country-item {
|
.country-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
Loading…
Reference in New Issue