Skip to content

Commit 37d35f7

Browse files
committed
feat: table add filterResetToDefaultFilteredValue & filterSearch funcion
1 parent a4b6c0a commit 37d35f7

File tree

11 files changed

+195
-39
lines changed

11 files changed

+195
-39
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<docs>
2+
---
3+
order: 6.2
4+
version: 4.19.0
5+
title:
6+
en-US: Filter search
7+
zh-CN: 自定义筛选的搜索
8+
---
9+
10+
## zh-CN
11+
12+
`filterSearch` 用于开启筛选项的搜索,通过 `filterSearch:(input, record) => boolean` 设置自定义筛选方法
13+
14+
## en-US
15+
16+
`filterSearch` is used to enable search of filter items, and you can set a custom filter method through `filterSearch:(input, record) => boolean`.
17+
18+
</docs>
19+
20+
<template>
21+
<a-table :columns="columns" :data-source="data" @change="onChange"></a-table>
22+
</template>
23+
<script lang="ts">
24+
import { defineComponent } from 'vue';
25+
import type { TableProps } from 'ant-design-vue';
26+
27+
export default defineComponent({
28+
setup() {
29+
const columns: TableProps['columns'] = [
30+
{
31+
title: 'Name',
32+
dataIndex: 'name',
33+
filters: [
34+
{
35+
text: 'Joe',
36+
value: 'Joe',
37+
},
38+
{
39+
text: 'Category 1',
40+
value: 'Category 1',
41+
},
42+
{
43+
text: 'Category 2',
44+
value: 'Category 2',
45+
},
46+
],
47+
filterMode: 'tree',
48+
filterSearch: true,
49+
onFilter: (value, record) => record.name.startsWith(value),
50+
width: '30%',
51+
},
52+
{
53+
title: 'Age',
54+
dataIndex: 'age',
55+
sorter: (a, b) => a.age - b.age,
56+
},
57+
{
58+
title: 'Address',
59+
dataIndex: 'address',
60+
filters: [
61+
{
62+
text: 'London',
63+
value: 'London',
64+
},
65+
{
66+
text: 'New York',
67+
value: 'New York',
68+
},
69+
],
70+
onFilter: (value, record) => record.address.startsWith(value),
71+
filterSearch: (input, filter) => (filter.value as string).indexOf(input) > -1,
72+
width: '40%',
73+
},
74+
];
75+
const data = [
76+
{
77+
key: '1',
78+
name: 'John Brown',
79+
age: 32,
80+
address: 'New York No. 1 Lake Park',
81+
},
82+
{
83+
key: '2',
84+
name: 'Jim Green',
85+
age: 42,
86+
address: 'London No. 1 Lake Park',
87+
},
88+
{
89+
key: '3',
90+
name: 'Joe Black',
91+
age: 32,
92+
address: 'Sidney No. 1 Lake Park',
93+
},
94+
{
95+
key: '4',
96+
name: 'Jim Red',
97+
age: 32,
98+
address: 'London No. 2 Lake Park',
99+
},
100+
];
101+
102+
function onChange(pagination, filters, sorter, extra) {
103+
console.log('params', pagination, filters, sorter, extra);
104+
}
105+
106+
return {
107+
data,
108+
columns,
109+
onChange,
110+
};
111+
},
112+
});
113+
</script>

components/table/demo/index.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<Head />
1919
<CustomFilterPanel />
2020
<ResetFilter />
21+
<filterSearchVue />
2122
<RowSelectionAndOperation />
2223
<RowSelectionCustom />
2324
<RowSelection />
@@ -61,6 +62,7 @@ import Summary from './summary.vue';
6162
import Sticky from './sticky.vue';
6263
import ResizableColumn from './resizable-column.vue';
6364
import Responsive from './responsive.vue';
65+
import filterSearchVue from './filter-search.vue';
6466
import CN from '../index.zh-CN.md';
6567
import US from '../index.en-US.md';
6668
import { defineComponent } from 'vue';
@@ -69,6 +71,7 @@ export default defineComponent({
6971
CN,
7072
US,
7173
components: {
74+
filterSearchVue,
7275
Basic,
7376
Ellipsis,
7477
Ajax,

components/table/hooks/useFilter/FilterDropdown.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,12 @@ export interface FilterDropdownProps<RecordType> {
108108
filterState?: FilterState<RecordType>;
109109
filterMultiple: boolean;
110110
filterMode?: 'menu' | 'tree';
111-
filterSearch?: boolean;
111+
filterSearch?: FilterSearchType;
112112
columnKey: Key;
113113
triggerFilter: (filterState: FilterState<RecordType>) => void;
114114
locale: TableLocale;
115115
getPopupContainer?: GetPopupContainer;
116+
filterResetToDefaultFilteredValue?: boolean;
116117
}
117118

118119
export default defineComponent<FilterDropdownProps<any>>({
@@ -266,7 +267,11 @@ export default defineComponent<FilterDropdownProps<any>>({
266267
triggerVisible(false);
267268
}
268269
searchValue.value = '';
269-
filteredKeys.value = [];
270+
if (props.column.filterResetToDefaultFilteredValue) {
271+
filteredKeys.value = (props.column.defaultFilteredValue || []).map(key => String(key));
272+
} else {
273+
filteredKeys.value = [];
274+
}
270275
};
271276

272277
const doFilter = ({ closeDropdown } = { closeDropdown: true }) => {
@@ -432,7 +437,17 @@ export default defineComponent<FilterDropdownProps<any>>({
432437
</>
433438
);
434439
};
440+
const resetDisabled = computed(() => {
441+
const selectedKeys = filteredKeys.value;
442+
if (props.column.filterResetToDefaultFilteredValue) {
443+
return isEqual(
444+
(props.column.defaultFilteredValue || []).map(key => String(key)),
445+
selectedKeys,
446+
);
447+
}
435448

449+
return selectedKeys.length === 0;
450+
});
436451
return () => {
437452
const { tablePrefixCls, prefixCls, column, dropdownPrefixCls, locale, getPopupContainer } =
438453
props;
@@ -453,15 +468,14 @@ export default defineComponent<FilterDropdownProps<any>>({
453468
} else if (filterDropdownRef.value) {
454469
dropdownContent = filterDropdownRef.value;
455470
} else {
456-
const selectedKeys = filteredKeys.value as any;
457471
dropdownContent = (
458472
<>
459473
{getFilterComponent()}
460474
<div class={`${prefixCls}-dropdown-btns`}>
461475
<Button
462476
type="link"
463477
size="small"
464-
disabled={selectedKeys.length === 0}
478+
disabled={resetDisabled.value}
465479
onClick={() => onReset()}
466480
>
467481
{locale.filterReset}

components/table/hooks/useFilter/FilterSearch.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { PropType } from 'vue';
22
import { defineComponent } from 'vue';
33
import SearchOutlined from '@ant-design/icons-vue/SearchOutlined';
4-
import type { TableLocale } from '../../interface';
4+
import type { FilterSearchType, TableLocale } from '../../interface';
55
import Input from '../../../input';
66

77
export default defineComponent({
@@ -10,7 +10,7 @@ export default defineComponent({
1010
props: {
1111
value: String,
1212
onChange: Function as PropType<(e: InputEvent) => void>,
13-
filterSearch: Boolean,
13+
filterSearch: [Boolean, Function] as PropType<FilterSearchType>,
1414
tablePrefixCls: String,
1515
locale: { type: Object as PropType<TableLocale>, default: undefined as TableLocale },
1616
},

components/table/hooks/useFilter/index.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -218,23 +218,25 @@ function useFilter<RecordType>({
218218
const mergedFilterStates = computed(() => {
219219
const collectedStates = collectFilterStates(mergedColumns.value, false);
220220

221-
const filteredKeysIsNotControlled = collectedStates.every(
222-
({ filteredKeys }) => filteredKeys === undefined,
223-
);
221+
let filteredKeysIsAllNotControlled = true;
222+
let filteredKeysIsAllControlled = true;
223+
collectedStates.forEach(({ filteredKeys }) => {
224+
if (filteredKeys !== undefined) {
225+
filteredKeysIsAllNotControlled = false;
226+
} else {
227+
filteredKeysIsAllControlled = false;
228+
}
229+
});
224230

225231
// Return if not controlled
226-
if (filteredKeysIsNotControlled) {
232+
if (filteredKeysIsAllNotControlled) {
227233
return filterStates.value;
228234
}
229235

230-
const filteredKeysIsAllControlled = collectedStates.every(
231-
({ filteredKeys }) => filteredKeys !== undefined,
232-
);
233-
234236
devWarning(
235-
filteredKeysIsNotControlled || filteredKeysIsAllControlled,
237+
filteredKeysIsAllControlled,
236238
'Table',
237-
'`FilteredKeys` should all be controlled or not controlled.',
239+
'Columns should all contain `filteredValue` or not contain `filteredValue`.',
238240
);
239241

240242
return collectedStates;

components/table/hooks/useSorter.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type { Ref } from 'vue';
2020
import { computed } from 'vue';
2121
import useState from '../../_util/hooks/useState';
2222
import type { DefaultRecordType } from '../../vc-table/interface';
23+
import KeyCode from '../../_util/KeyCode';
2324

2425
const ASCEND = 'ascend';
2526
const DESCEND = 'descend';
@@ -108,8 +109,8 @@ function collectSortStates<RecordType>(
108109
function injectSorter<RecordType>(
109110
prefixCls: string,
110111
columns: ColumnsType<RecordType>,
111-
sorterSates: SortState<RecordType>[],
112-
triggerSorter: (sorterSates: SortState<RecordType>) => void,
112+
sorterStates: SortState<RecordType>[],
113+
triggerSorter: (sorterStates: SortState<RecordType>) => void,
113114
defaultSortDirections: SortOrder[],
114115
tableLocale?: TableLocale,
115116
tableShowSorterTooltip?: boolean | TooltipProps,
@@ -126,7 +127,7 @@ function injectSorter<RecordType>(
126127
? tableShowSorterTooltip
127128
: newColumn.showSorterTooltip;
128129
const columnKey = getColumnKey(newColumn, columnPos);
129-
const sorterState = sorterSates.find(({ key }) => key === columnKey);
130+
const sorterState = sorterStates.find(({ key }) => key === columnKey);
130131
const sorterOrder = sorterState ? sorterState.sortOrder : null;
131132
const nextSortOrder = nextSortDirection(sortDirections, sorterOrder);
132133
const upNode = sortDirections.includes(ASCEND) && (
@@ -182,6 +183,7 @@ function injectSorter<RecordType>(
182183
customHeaderCell: col => {
183184
const cell = (column.customHeaderCell && column.customHeaderCell(col)) || {};
184185
const originOnClick = cell.onClick;
186+
const originOKeyDown = cell.onKeydown;
185187
cell.onClick = (event: MouseEvent) => {
186188
triggerSorter({
187189
column,
@@ -194,9 +196,29 @@ function injectSorter<RecordType>(
194196
originOnClick(event);
195197
}
196198
};
199+
cell.onKeydown = (event: KeyboardEvent) => {
200+
if (event.keyCode === KeyCode.ENTER) {
201+
triggerSorter({
202+
column,
203+
key: columnKey,
204+
sortOrder: nextSortOrder,
205+
multiplePriority: getMultiplePriority(column),
206+
});
207+
originOKeyDown?.(event);
208+
}
209+
};
197210

198-
cell.class = classNames(cell.class, `${prefixCls}-column-has-sorters`);
211+
// Inform the screen-reader so it can tell the visually impaired user which column is sorted
212+
if (sorterOrder) {
213+
if (sorterOrder === 'ascend') {
214+
cell['aria-sort'] = 'ascending';
215+
} else {
216+
cell['aria-sort'] = 'descending';
217+
}
218+
}
199219

220+
cell.class = classNames(cell.class, `${prefixCls}-column-has-sorters`);
221+
cell.tabindex = 0;
200222
return cell;
201223
},
202224
};
@@ -208,7 +230,7 @@ function injectSorter<RecordType>(
208230
children: injectSorter(
209231
prefixCls,
210232
newColumn.children,
211-
sorterSates,
233+
sorterStates,
212234
triggerSorter,
213235
defaultSortDirections,
214236
tableLocale,

components/table/index.en-US.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ One of the Table `columns` prop for describing the table's columns, Column has t
157157
| customRender | Renderer of the table cell. The return value should be a VNode | Function({text, record, index}) {} | - | |
158158
| dataIndex | Display field of the data record, support nest path by string array | string \| string\[] | - | |
159159
| defaultFilteredValue | Default filtered values | string\[] | - | 1.5.0 |
160+
| filterResetToDefaultFilteredValue | click the reset button, whether to restore the default filter | boolean | false | 3.3.0 |
160161
| defaultSortOrder | Default order of sorted values: `'ascend'` `'descend'` `null` | string | - | |
161162
| ellipsis | ellipsize cell content, not working with sorter and filters for now.<br />tableLayout would be `fixed` when `ellipsis` is true. | boolean | false | 1.5.0 |
162163
| ellipsis | The ellipsis cell content, not working with sorter and filters for now.<br />tableLayout would be `fixed` when `ellipsis` is `true` or `{ showTitle?: boolean }` | boolean \| {showTitle?: boolean } | false | 3.0 |
@@ -168,7 +169,7 @@ One of the Table `columns` prop for describing the table's columns, Column has t
168169
| filterMode | To specify the filter interface | 'menu' \| 'tree' | 'menu' | 3.0 |
169170
| filterMultiple | Whether multiple filters can be selected | boolean | `true` | |
170171
| filters | Filter menu config | object\[] | - | |
171-
| filterSearch | Whether to be searchable for filter menu | Boolean | false | 3.0 |
172+
| filterSearch | Whether to be searchable for filter menu | boolean \| function(input, filter):boolean | false | boolean: 3.0 function: 3.3.0 |
172173
| fixed | Set column to be fixed: `true`(same as left) `'left'` `'right'` | boolean\|string | `false` | |
173174
| key | Unique key of this column, you can ignore this prop if you've set a unique `dataIndex` | string | - | |
174175
| maxWidth | Drag the maximum width of the column, it will be affected by the automatic adjustment and distribution of the table width | number | - | 3.0 |

components/table/index.zh-CN.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/f-SbcX2Lx/Table.svg
162162
| customRender | 生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引 | Function({text, record, index, column}) {} | - | |
163163
| dataIndex | 列数据在数据项中对应的路径,支持通过数组查询嵌套路径 | string \| string\[] | - | |
164164
| defaultFilteredValue | 默认筛选值 | string\[] | - | 1.5.0 |
165+
| filterResetToDefaultFilteredValue | 点击重置按钮的时候,是否恢复默认筛选值 | boolean | false | 3.3.0 |
165166
| defaultSortOrder | 默认排序顺序 | `ascend` \| `descend` | - | |
166167
| ellipsis | 超过宽度将自动省略,暂不支持和排序筛选一起使用。<br />设置为 `true``{ showTitle?: boolean }` 时,表格布局将变成 `tableLayout="fixed"`| boolean \| { showTitle?: boolean } | false | 3.0 |
167168
| filterDropdown | 可以自定义筛选菜单,此函数只负责渲染图层,需要自行编写各种交互 | VNode | - | |
@@ -172,7 +173,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/f-SbcX2Lx/Table.svg
172173
| filterMode | 指定筛选菜单的用户界面 | 'menu' \| 'tree' | 'menu' | 3.0 |
173174
| filterMultiple | 是否多选 | boolean | true | |
174175
| filters | 表头的筛选菜单项 | object\[] | - | |
175-
| filterSearch | 筛选菜单项是否可搜索 | Boolean | false | 3.0 |
176+
| filterSearch | 筛选菜单项是否可搜索 | boolean \| function(input, filter):boolean | false | boolean:3.0 function:3.3.0 |
176177
| fixed | 列是否固定,可选 `true`(等效于 left) `'left'` `'right'` | boolean\|string | false | |
177178
| key | Vue 需要的 key,如果已经设置了唯一的 `dataIndex`,可以忽略这个属性 | string | - | |
178179
| maxWidth | 拖动列最大宽度,会受到表格自动调整分配宽度影响 | number | - | 3.0 |

components/table/interface.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export type ColumnTitle<RecordType> = VueNode | ((props: ColumnTitleProps<Record
7373

7474
export type FilterValue = (Key | boolean)[];
7575
export type FilterKey = Key[] | null;
76-
export type FilterSearchType = boolean | ((input: string, record: {}) => boolean);
76+
export type FilterSearchType = boolean | ((input: string, record: ColumnFilterItem) => boolean);
7777
export interface FilterConfirmProps {
7878
closeDropdown: boolean;
7979
}
@@ -89,7 +89,8 @@ export interface FilterDropdownProps<RecordType> {
8989
column: ColumnType<RecordType>;
9090
}
9191

92-
export interface ColumnType<RecordType = DefaultRecordType> extends RcColumnType<RecordType> {
92+
export interface ColumnType<RecordType = DefaultRecordType>
93+
extends Omit<RcColumnType<RecordType>, 'title'> {
9394
title?: ColumnTitle<RecordType>;
9495
// Sorter
9596
sorter?:
@@ -114,11 +115,11 @@ export interface ColumnType<RecordType = DefaultRecordType> extends RcColumnType
114115
defaultFilteredValue?: FilterValue | null;
115116
filterIcon?: VueNode | ((opt: { filtered: boolean; column: ColumnType }) => VueNode);
116117
filterMode?: 'menu' | 'tree';
117-
filterSearch?: boolean;
118+
filterSearch?: FilterSearchType;
118119
onFilter?: (value: string | number | boolean, record: RecordType) => boolean;
119120
filterDropdownVisible?: boolean;
120121
onFilterDropdownVisibleChange?: (visible: boolean) => void;
121-
122+
filterResetToDefaultFilteredValue?: boolean;
122123
// Responsive
123124
responsive?: Breakpoint[];
124125
}

0 commit comments

Comments
 (0)