Skip to content

Commit

Permalink
feat(vue-grid): add the Advanced filtering feature (#1186)
Browse files Browse the repository at this point in the history
  • Loading branch information
MaximKudriavtsev authored Jun 21, 2018
1 parent c19907f commit b5a468c
Show file tree
Hide file tree
Showing 26 changed files with 932 additions and 110 deletions.
2 changes: 2 additions & 0 deletions packages/dx-react-grid/docs/reference/table-filter-row.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ iconComponent | ComponentType<[TableFilterRow.IconProps](#tablefilterrowiconp
value | string | The currently selected filter operation.
availableValues | Array<string> | The list of available filter operations.
onChange | (value: string) => void | Handles filter operation changes.
disabled | boolean | Specifies whether the FilterSelector is disabled.
getMessage | ([messageKey](#localization-messages): string) => string | Returns the specified localization message.

### TableFilterRow.IconProps

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ export default {
showSortingControls
showGroupingControls
/>
<dx-table-filter-row />
<dx-table-filter-row
showFilterSelector
/>
<dx-table-selection
showSelectAll
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import {
DxDataTypeProvider,
DxFilteringState,
DxIntegratedFiltering,
} from '@devexpress/dx-vue-grid';
import {
DxGrid,
DxTable,
DxTableHeaderRow,
DxTableFilterRow,
} from '@devexpress/dx-vue-grid-bootstrap4';

import {
generateRows,
globalSalesValues,
} from '../../../demo-data/generator';

const MyDateFilterCell = {
template: `
<span class="d-block oi oi-calendar" />
`,
};

const FilterIcon = {
props: ['type'],
computed: {
componentId() {
return this.type === 'month' ? 'my-date-filter-cell' : 'dx-icon';
},
},
template: `
<component
:is="componentId"
v-bind="$attrs"
v-on="$listeners"
:type="type"
/>
`,
components: {
DxIcon: DxTableFilterRow.components.DxIcon,
MyDateFilterCell,
},
};

const CurrencyFormatter = {
props: ['value'],
template: `
<b style="color: darkblue">\${{ value }}</b>
`,
};

const CurrencyTypeProvider = {
template: `
<dx-data-type-provider
:formatterComponent="$options.components.CurrencyFormatter"
:availableFilterOperations="$attrs.availableFilterOperations"
:for="$attrs.for"
/>
`,
components: {
DxDataTypeProvider,
CurrencyFormatter,
},
};

const DateFormatter = {
props: ['value'],
template: `
<span>{{ value.replace(/(\\d{4})-(\\d{2})-(\\d{2})/, '$3.$2.$1') }}</span>
`,
};

const DateTypeProvider = {
template: `
<dx-data-type-provider
:formatterComponent="$options.components.DateFormatter"
:availableFilterOperations="$attrs.availableFilterOperations"
:for="$attrs.for"
/>
`,
components: {
DxDataTypeProvider,
DateFormatter,
},
};

export default {
data() {
return {
columns: [
{ name: 'customer', title: 'Customer' },
{ name: 'product', title: 'Product' },
{ name: 'saleDate', title: 'Sale Date' },
{ name: 'amount', title: 'Sale Amount' },
],
rows: generateRows({ columnValues: globalSalesValues, length: 8 }),
tableColumnExtensions: [
{ columnName: 'amount', align: 'right' },
],
filters: [],
dateColumns: ['saleDate'],
currencyColumns: ['amount'],
dateFilterOperations: ['month', 'contains', 'startsWith', 'endsWith'],
currencyFilterOperations: ['equal', 'notEqual', 'greaterThan', 'greaterThanOrEqual', 'lessThan', 'lessThanOrEqual'],
filteringColumnExtensions: [
{
columnName: 'saleDate',
predicate: (value, filter, row) => {
if (!filter.value.length) return true;
if (filter && filter.operation === 'month') {
const month = parseInt(value.split('-')[1], 10);
return month === parseInt(filter.value, 10);
}
return DxIntegratedFiltering.defaultPredicate(value, filter, row);
},
},
],
filterMessages: { month: 'Month equals' },
};
},
template: `
<div class="card">
<dx-grid
:rows="rows"
:columns="columns"
>
<currency-type-provider
:for="currencyColumns"
:availableFilterOperations="currencyFilterOperations"
/>
<date-type-provider
:for="dateColumns"
:availableFilterOperations="dateFilterOperations"
/>
<dx-filtering-state
:filters.sync="filters"
/>
<dx-integrated-filtering
:columnExtensions="filteringColumnExtensions"
/>
<dx-table
:columnExtensions="tableColumnExtensions"
/>
<dx-table-filter-row
showFilterSelector
:iconComponent="$options.components.FilterIcon"
:messages="filterMessages"
/>
<dx-table-header-row />
</dx-grid>
</div>
`,
components: {
DxGrid,
DxTable,
DxTableHeaderRow,
CurrencyTypeProvider,
DateTypeProvider,
DxFilteringState,
DxIntegratedFiltering,
DxTableFilterRow,
FilterIcon,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const MyUnitsFilterCell = {
inheritAttrs: false,
props: ['filter'],
template: `
<dx-cell
<th
v-bind="$attrs"
v-on="$listeners"
>
Expand All @@ -28,18 +28,16 @@ const MyUnitsFilterCell = {
:value="filter ? filter.value : ''"
min="1"
max="4"
placeholder="Filter..."
@change="e => this.$emit('filter', e.target.value ? { value: e.target.value } : null)"
/>
</dx-cell>
</th>
`,
components: {
DxCell: DxTableFilterRow.components.DxCell,
},
};

const MyFilterCell = {
inheritAttrs: false,
props: ['column'],
props: ['column', 'getMessage'],
data() {
return {
componentId: this.column.name === 'units' ? 'my-units-filter-cell' : 'dx-cell',
Expand All @@ -51,7 +49,9 @@ const MyFilterCell = {
:column="column"
v-bind="$attrs"
v-on="$listeners"
/>
>
<slot />
</component>
`,
components: {
DxCell: DxTableFilterRow.components.DxCell,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const CurrencyEditor = {
style="'width': '100%'"
:value="value === undefined ? '' : value"
min="0"
placeholder="Filter..."
@change="handleChange"
/>
`,
Expand All @@ -42,10 +43,20 @@ const CurrencyFormatter = {
};

export const CurrencyTypeProvider = {
data() {
return ({
availableFilterOperations: [
'equal', 'notEqual',
'greaterThan', 'greaterThanOrEqual',
'lessThan', 'lessThanOrEqual',
],
});
},
template: `
<dx-data-type-provider
:formatterComponent="$options.components.CurrencyFormatter"
:editorComponent="$options.components.CurrencyEditor"
:availableFilterOperations="availableFilterOperations"
:for="$attrs.for"
/>
`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,26 @@ const PercentEditor = {
step="0.1"
min="0"
max="100"
placeholder="Filter..."
@change="handleChange"
/>
`,
};

export const PercentTypeProvider = {
data() {
return ({
availableFilterOperations: [
'equal', 'notEqual',
'greaterThan', 'greaterThanOrEqual',
'lessThan', 'lessThanOrEqual',
],
});
},
template: `
<dx-data-type-provider
:editorComponent="$options.components.PercentEditor"
:availableFilterOperations="availableFilterOperations"
:for="$attrs.for"
/>
`,
Expand Down
31 changes: 30 additions & 1 deletion packages/dx-vue-grid-bootstrap4/src/plugins/table-filter-row.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
import { DxTableFilterRow as DxTableFilterRowBase } from '@devexpress/dx-vue-grid';
import { TableFilterCell } from '../templates/table-filter-cell';
import { TableRow } from '../templates/table-row';
import { Editor } from '../templates/filter-row/editor';
import { FilterSelector } from '../templates/filter-row/filter-selector';
import { Icon } from '../templates/filter-row/icon';

const defaultMessages = {
filterPlaceholder: 'Filter...',
contains: 'Contains',
notContains: 'Does not contain',
startsWith: 'Starts with',
endsWith: 'Ends with',
equal: 'Equals',
notEqual: 'Does not equal',
greaterThan: 'Greater than',
greaterThanOrEqual: 'Greater than or equal to',
lessThan: 'Less than',
lessThanOrEqual: 'Less than or equal to',
};

export const DxTableFilterRow = {
name: 'DxTableFilterRow',
functional: true,
props: {
messages: {
type: Object,
},
},
render(h, context) {
return (
<DxTableFilterRowBase
cellComponent={TableFilterCell}
rowComponent={TableRow}
{...{ attrs: context.props, on: context.listeners }}
filterSelectorComponent={FilterSelector}
iconComponent={Icon}
editorComponent={Editor}
messages={{ ...defaultMessages, ...context.props.messages }}
{...{ attrs: context.data.attrs, on: context.listeners }}
/>
);
},
components: {
DxCell: TableFilterCell,
DxRow: TableRow,
DxEditor: Editor,
DxFilterSelector: FilterSelector,
DxIcon: Icon,
},
};
42 changes: 42 additions & 0 deletions packages/dx-vue-grid-bootstrap4/src/templates/filter-row/editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export const Editor = {
name: 'Editor',
inheritAttrs: false,
props: {
value: {
type: [Number, String],
default: '',
},
disabled: {
type: Boolean,
default: false,
},
getMessage: {
type: Function,
required: true,
},
},
methods: {
handleChange(e) {
this.$emit('changeValue', e.target.value);
},
},
render() {
const {
value,
disabled,
getMessage,
} = this;

return (
<input
{...{ attrs: { ...this.$attrs }, on: { ...this.$listeners } }}
type="text"
class="form-control"
value={value}
onInput={this.handleChange}
readOnly={disabled}
placeholder={getMessage('filterPlaceholder')}
/>
);
},
};
Loading

0 comments on commit b5a468c

Please sign in to comment.