mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-07 17:44:35 +08:00
Multiple row selection (#11406)
This PR intends to solve issue #11404 (Multiple row selection in table component). The Chinese documentation is missing from the PR. Could someone please add it ?
This commit is contained in:
parent
ecff4997d9
commit
08e83193f2
@ -35,7 +35,7 @@ export interface CheckboxChangeEvent {
|
||||
target: CheckboxChangeEventTarget;
|
||||
stopPropagation: () => void;
|
||||
preventDefault: () => void;
|
||||
nativeEvent: Event;
|
||||
nativeEvent: MouseEvent;
|
||||
}
|
||||
|
||||
export default class Checkbox extends React.Component<CheckboxProps, {}> {
|
||||
|
@ -38,5 +38,5 @@ export interface RadioChangeEvent {
|
||||
target: RadioChangeEventTarget;
|
||||
stopPropagation: () => void;
|
||||
preventDefault: () => void;
|
||||
nativeEvent: Event;
|
||||
nativeEvent: MouseEvent;
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
// 减少状态
|
||||
filters: this.getFiltersFromColumns(),
|
||||
pagination: this.getDefaultPagination(props),
|
||||
pivot: undefined,
|
||||
};
|
||||
|
||||
this.CheckboxPropsCache = {};
|
||||
@ -250,6 +251,11 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
}
|
||||
if (selectWay === 'onSelect' && rowSelection.onSelect) {
|
||||
rowSelection.onSelect(record!, checked!, selectedRows, nativeEvent!);
|
||||
} else if (selectWay === 'onSelectMulti' && rowSelection.onSelectMulti) {
|
||||
const changeRows = data.filter(
|
||||
(row, i) => changeRowKeys!.indexOf(this.getRecordKey(row, i)) >= 0,
|
||||
);
|
||||
rowSelection.onSelectMulti(checked!, selectedRows, changeRows);
|
||||
} else if (selectWay === 'onSelectAll' && rowSelection.onSelectAll) {
|
||||
const changeRows = data.filter(
|
||||
(row, i) => changeRowKeys!.indexOf(this.getRecordKey(row, i)) >= 0,
|
||||
@ -456,21 +462,67 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
const defaultSelection = this.store.getState().selectionDirty ? [] : this.getDefaultSelection();
|
||||
let selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection);
|
||||
let key = this.getRecordKey(record, rowIndex);
|
||||
if (checked) {
|
||||
selectedRowKeys.push(this.getRecordKey(record, rowIndex));
|
||||
} else {
|
||||
selectedRowKeys = selectedRowKeys.filter((i: string) => key !== i);
|
||||
const pivot = this.state.pivot;
|
||||
const rows = this.getFlatCurrentPageData();
|
||||
let realIndex = rowIndex;
|
||||
if (this.props.expandedRowRender) {
|
||||
realIndex = rows.findIndex(row => this.getRecordKey(row, rowIndex) === key);
|
||||
}
|
||||
|
||||
if (nativeEvent.shiftKey && pivot !== undefined && realIndex !== pivot) {
|
||||
const changeRowKeys = [];
|
||||
const direction = Math.sign(pivot - realIndex);
|
||||
const dist = Math.abs(pivot - realIndex);
|
||||
let step = 0;
|
||||
while (step <= dist) {
|
||||
const i = realIndex + (step * direction);
|
||||
step += 1;
|
||||
const row = rows[i];
|
||||
const rowKey = this.getRecordKey(row, i);
|
||||
const checkboxProps = this.getCheckboxPropsByItem(row, i);
|
||||
if (!checkboxProps.disabled) {
|
||||
if (selectedRowKeys.includes(rowKey)) {
|
||||
if (!checked) {
|
||||
selectedRowKeys = selectedRowKeys.filter((j: string) => rowKey !== j);
|
||||
changeRowKeys.push(rowKey);
|
||||
}
|
||||
} else if (checked) {
|
||||
selectedRowKeys.push(rowKey);
|
||||
changeRowKeys.push(rowKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ pivot: realIndex });
|
||||
this.store.setState({
|
||||
selectionDirty: true,
|
||||
});
|
||||
this.setSelectedRowKeys(selectedRowKeys, {
|
||||
selectWay: 'onSelectMulti',
|
||||
record,
|
||||
checked,
|
||||
changeRowKeys,
|
||||
nativeEvent,
|
||||
});
|
||||
} else {
|
||||
if (checked) {
|
||||
selectedRowKeys.push(this.getRecordKey(record, realIndex));
|
||||
} else {
|
||||
selectedRowKeys = selectedRowKeys.filter((i: string) => key !== i);
|
||||
}
|
||||
|
||||
this.setState({ pivot: realIndex });
|
||||
this.store.setState({
|
||||
selectionDirty: true,
|
||||
});
|
||||
this.setSelectedRowKeys(selectedRowKeys, {
|
||||
selectWay: 'onSelect',
|
||||
record,
|
||||
checked,
|
||||
changeRowKeys: void(0),
|
||||
nativeEvent,
|
||||
});
|
||||
}
|
||||
this.store.setState({
|
||||
selectionDirty: true,
|
||||
});
|
||||
this.setSelectedRowKeys(selectedRowKeys, {
|
||||
selectWay: 'onSelect',
|
||||
record,
|
||||
checked,
|
||||
changeRowKeys: void(0),
|
||||
nativeEvent,
|
||||
});
|
||||
}
|
||||
|
||||
handleRadioSelect = (record: T, rowIndex: number, e: RadioChangeEvent) => {
|
||||
@ -599,11 +651,11 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
|
||||
renderSelectionBox = (type: RowSelectionType | undefined) => {
|
||||
return (_: any, record: T, index: number) => {
|
||||
let rowIndex = this.getRecordKey(record, index); // 从 1 开始
|
||||
const rowKey = this.getRecordKey(record, index);
|
||||
const props = this.getCheckboxPropsByItem(record, index);
|
||||
const handleChange = (e: RadioChangeEvent | CheckboxChangeEvent) => {
|
||||
type === 'radio' ? this.handleRadioSelect(record, rowIndex, e) :
|
||||
this.handleSelect(record, rowIndex, e);
|
||||
type === 'radio' ? this.handleRadioSelect(record, index, e) :
|
||||
this.handleSelect(record, index, e);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -611,7 +663,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
<SelectionBox
|
||||
type={type}
|
||||
store={this.store}
|
||||
rowIndex={rowIndex}
|
||||
rowIndex={rowKey}
|
||||
onChange={handleChange}
|
||||
defaultSelection={this.getDefaultSelection()}
|
||||
{...props}
|
||||
|
@ -162,6 +162,36 @@ describe('Table.rowSelection', () => {
|
||||
expect(handleSelect.mock.calls[0][3].type).toBe('change');
|
||||
});
|
||||
|
||||
it('fires selectMulti event', () => {
|
||||
const handleSelectMulti = jest.fn();
|
||||
const handleSelect = jest.fn();
|
||||
const rowSelection = {
|
||||
onSelect: handleSelect,
|
||||
onSelectMulti: handleSelectMulti,
|
||||
};
|
||||
const wrapper = mount(createTable({ rowSelection }));
|
||||
|
||||
wrapper.find('input').at(1).simulate('change', {
|
||||
target: { checked: true },
|
||||
nativeEvent: { shiftKey: true },
|
||||
});
|
||||
expect(handleSelect).toBeCalled();
|
||||
|
||||
wrapper.find('input').at(3).simulate('change', {
|
||||
target: { checked: true },
|
||||
nativeEvent: { shiftKey: true },
|
||||
});
|
||||
expect(handleSelectMulti).toBeCalledWith(true,
|
||||
[data[0], data[1], data[2]], [data[1], data[2]]);
|
||||
|
||||
wrapper.find('input').at(1).simulate('change', {
|
||||
target: { checked: false },
|
||||
nativeEvent: { shiftKey: true },
|
||||
});
|
||||
expect(handleSelectMulti).toBeCalledWith(false,
|
||||
[], [data[0], data[1], data[2]]);
|
||||
});
|
||||
|
||||
it('fires selectAll event', () => {
|
||||
const handleSelectAll = jest.fn();
|
||||
const rowSelection = {
|
||||
|
@ -162,6 +162,7 @@ Properties for row selection.
|
||||
| type | `checkbox` or `radio` | `checkbox` \| `radio` | `checkbox` |
|
||||
| onChange | Callback executed when selected rows change | Function(selectedRowKeys, selectedRows) | - |
|
||||
| onSelect | Callback executed when select/deselect one row | Function(record, selected, selectedRows, nativeEvent) | - |
|
||||
| onSelectMulti | Callback executed when multiple rows are selected/unselected | Function(selected, selectedRows, changeRows) | - |
|
||||
| onSelectAll | Callback executed when select/deselect all rows | Function(selected, selectedRows, changeRows) | - |
|
||||
| onSelectInvert | Callback executed when row selection is inverted | Function(selectedRows) | - |
|
||||
|
||||
|
@ -62,7 +62,7 @@ export interface TableLocale {
|
||||
export type RowSelectionType = 'checkbox' | 'radio';
|
||||
export type SelectionSelectFn<T> = (record: T, selected: boolean, selectedRows: Object[], nativeEvent: Event) => any;
|
||||
|
||||
export type TableSelectWay = 'onSelect' | 'onSelectAll' | 'onSelectInvert';
|
||||
export type TableSelectWay = 'onSelect' | 'onSelectMulti' | 'onSelectAll' | 'onSelectInvert';
|
||||
|
||||
export interface TableRowSelection<T> {
|
||||
type?: RowSelectionType;
|
||||
@ -70,12 +70,14 @@ export interface TableRowSelection<T> {
|
||||
onChange?: (selectedRowKeys: string[] | number[], selectedRows: Object[]) => void;
|
||||
getCheckboxProps?: (record: T) => Object;
|
||||
onSelect?: SelectionSelectFn<T>;
|
||||
onSelectMulti?: (selected: boolean, selectedRows: Object[], changeRows: Object[]) => void;
|
||||
onSelectAll?: (selected: boolean, selectedRows: Object[], changeRows: Object[]) => void;
|
||||
onSelectInvert?: (selectedRows: Object[]) => void;
|
||||
selections?: SelectionItem[] | boolean;
|
||||
hideDefaultSelections?: boolean;
|
||||
fixed?: boolean;
|
||||
columnWidth?: string | number;
|
||||
selectWay?: TableSelectWay;
|
||||
}
|
||||
export type SortOrder = 'descend' | 'ascend';
|
||||
export interface SorterResult<T> {
|
||||
@ -138,6 +140,7 @@ export interface TableState<T> {
|
||||
filters: TableStateFilters;
|
||||
sortColumn: ColumnProps<T> | null;
|
||||
sortOrder?: SortOrder;
|
||||
pivot?: number;
|
||||
}
|
||||
|
||||
export type SelectionItemSelectFn = (key: string[]) => any;
|
||||
|
Loading…
Reference in New Issue
Block a user