Skip to content

Commit

Permalink
implement single row selection (#821)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbetancur committed Jun 13, 2021
1 parent 6a5668b commit 618f885
Show file tree
Hide file tree
Showing 11 changed files with 401 additions and 7 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ When the breakpoint is reached the column will be hidden. These are the built-in
| selectableRows | bool | no | false | Whether to show selectable checkboxes |
| selectableRowsVisibleOnly | bool | no | false | When using using `pagination` and `selectableRows` all rows in `data` are selected by default if you check the select all rows checkbox. For example, if you have 20 rows and with `pagination` 10 rows per page clicking on the select all checkbox results in 20 rows being selected (i.e. rows are selected that are not in the view). However, with `selectableRowsVisibleOnly` only the 10 rows that are visible (those that are on the current page) are allowed to be selected using select all. <br /><br />Things to note when using `selectableRowsVisibleOnly`: <br /> 1. When you sort then selected items will be cleared <br />2. When using `sortServer` for server side sorting you do not need to set `selectableRowsVisibleOnly` as the behavior is implicit |
| selectableRowsHighlight | bool | no | false | Highlight a row when it is selected |
| selectableRowsSingle | bool | no | false | Switches to single row selection mode. `onSelectedRowsChange` will still return an array of `selectedRows`, but it will only be a single array item |
| selectableRowsNoSelectAll | bool | no | false | Whether to show the select all rows checkbox |
| clearSelectedRows | bool | no | false | Toggling this property clears the selectedRows. If you use redux or react state you need to make sure that you pass a toggled value or the component will not update. See [Clearing Selected Rows](#clearing-selected-rows)|
| onSelectedRowsChange | func | no | | Callback that fires anytime the rows selected state changes. Returns ({ allSelected, selectedCount, selectedRows }).<br /><br />**Note** It's highly recommended that you memoize the callback that you pass to `onSelectedRowsChange` if it updates the state of your parent component. This prevents `DataTable` from unnecessary re-renders every time your parent component is re-rendered |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-data-table-component",
"version": "7.0.0-alpha-13",
"version": "7.0.0-alpha-14",
"description": "A declarative react based data table",
"main": "dist/index.cjs.js",
"module": "dist/index.es.js",
Expand Down
8 changes: 5 additions & 3 deletions src/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function DataTable<T extends RowRecord>(props: TableProps<T>): JSX.Element {
pointerOnHover = defaultProps.pointerOnHover,
dense = defaultProps.dense,
selectableRows = defaultProps.selectableRows,
selectableRowsSingle = defaultProps.selectableRowsSingle,
selectableRowsHighlight = defaultProps.selectableRowsHighlight,
selectableRowsNoSelectAll = defaultProps.selectableRowsNoSelectAll,
selectableRowsVisibleOnly = defaultProps.selectableRowsVisibleOnly,
Expand Down Expand Up @@ -284,10 +285,10 @@ function DataTable<T extends RowRecord>(props: TableProps<T>): JSX.Element {

React.useEffect(() => {
dispatch({ type: 'CLEAR_SELECTED_ROWS', selectedRowsFlag: clearSelectedRows });
}, [clearSelectedRows]);
}, [selectableRowsSingle, clearSelectedRows]);

React.useEffect(() => {
if (selectableRowSelected) {
if (selectableRowSelected && !selectableRowsSingle) {
const preSelectedRows = rows.filter(row => selectableRowSelected(row));

dispatch({ type: 'SELECT_MULTIPLE_ROWS', keyField, selectedRows: preSelectedRows, rows: rows, mergeSelections });
Expand All @@ -297,7 +298,7 @@ function DataTable<T extends RowRecord>(props: TableProps<T>): JSX.Element {
}, [rows]);

const rowData = selectableRowsVisibleOnly ? calculatedRows : rows;
const showSelectAll = persistSelectedOnPageChange || selectableRowsNoSelectAll;
const showSelectAll = persistSelectedOnPageChange || selectableRowsSingle || selectableRowsNoSelectAll;

return (
<ThemeProvider theme={currentTheme}>
Expand Down Expand Up @@ -420,6 +421,7 @@ function DataTable<T extends RowRecord>(props: TableProps<T>): JSX.Element {
selectableRowsComponent={selectableRowsComponent}
selectableRowsComponentProps={selectableRowsComponentProps}
selectableRowDisabled={selectableRowDisabled}
selectableRowsSingle={selectableRowsSingle}
striped={striped}
onRowExpandToggled={onRowExpandToggled}
onRowClicked={handleRowClicked}
Expand Down
7 changes: 5 additions & 2 deletions src/DataTable/TableCellCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import styled from 'styled-components';
import { CellBase } from './Cell';
import Checkbox from './Checkbox';
import { RowRecord, RowState, SingleRowAction } from './types';
import { RowRecord, RowState, SingleRowAction, ComponentProps } from './types';

const TableCellCheckboxStyle = styled(CellBase)`
flex: 0 0 48px;
Expand All @@ -19,7 +19,8 @@ type TableCellCheckboxProps<T> = {
rowCount: number;
selected: boolean;
selectableRowsComponent: 'input' | React.ReactNode;
selectableRowsComponentProps: Record<string, unknown>;
selectableRowsComponentProps: ComponentProps;
selectableRowsSingle: boolean;
selectableRowDisabled: RowState<T>;
onSelectedRow: (action: SingleRowAction<T>) => void;
};
Expand All @@ -31,6 +32,7 @@ function TableCellCheckbox<T extends RowRecord>({
selected,
selectableRowsComponent,
selectableRowsComponentProps,
selectableRowsSingle,
selectableRowDisabled,
onSelectedRow,
}: TableCellCheckboxProps<T>): JSX.Element {
Expand All @@ -43,6 +45,7 @@ function TableCellCheckbox<T extends RowRecord>({
isSelected: selected,
keyField,
rowCount,
singleSelect: selectableRowsSingle,
});
};

Expand Down
3 changes: 3 additions & 0 deletions src/DataTable/TableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type DProps<T> = Pick<
| 'selectableRowsComponent'
| 'selectableRowsComponentProps'
| 'selectableRowsHighlight'
| 'selectableRowsSingle'
| 'striped'
>;

Expand Down Expand Up @@ -113,6 +114,7 @@ function TableRow<T extends RowRecord>({
selectableRowsComponent,
selectableRowsComponentProps,
selectableRowsHighlight = false,
selectableRowsSingle = false,
selected,
striped = false,
}: TableRowProps<T>): JSX.Element {
Expand Down Expand Up @@ -184,6 +186,7 @@ function TableRow<T extends RowRecord>({
selectableRowsComponent={selectableRowsComponent}
selectableRowsComponentProps={selectableRowsComponentProps}
selectableRowDisabled={selectableRowDisabled}
selectableRowsSingle={selectableRowsSingle}
onSelectedRow={onSelectedRow}
/>
)}
Expand Down
32 changes: 32 additions & 0 deletions src/DataTable/__tests__/DataTable.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,38 @@ describe('DataTable::selectableRows', () => {
expect(container.firstChild).toMatchSnapshot();
});

test('should only select a single row when selectableRowsSingle is true and a row is selected', () => {
const mock = dataMock();
const { container } = render(
<DataTable data={mock.data} columns={mock.columns} selectableRows selectableRowsSingle />,
);

const rowCheck1 = container.querySelector('input[name="select-row-1"]') as HTMLInputElement;
const rowCheck2 = container.querySelector('input[name="select-row-2"]') as HTMLInputElement;

fireEvent.click(rowCheck1);
fireEvent.click(rowCheck2);

expect(rowCheck1.checked).toBe(false);
expect(rowCheck2.checked).toBe(true);
expect(container.firstChild).toMatchSnapshot();
});

test('should clear all rows selectableRowsSingle is changed', () => {
const mock = dataMock();
const { container, rerender } = render(<DataTable data={mock.data} columns={mock.columns} selectableRows />);
const rowCheck1 = container.querySelector('input[name="select-row-1"]') as HTMLInputElement;
const rowCheck2 = container.querySelector('input[name="select-row-2"]') as HTMLInputElement;

fireEvent.click(rowCheck1);
fireEvent.click(rowCheck2);

rerender(<DataTable data={mock.data} columns={mock.columns} selectableRows selectableRowsSingle />);

expect(rowCheck1.checked).toBe(false);
expect(rowCheck2.checked).toBe(false);
});

test('should not render a select all checkbox when selectableRowsNoSelectAll is true', () => {
const mock = dataMock();
const { container } = render(
Expand Down
Loading

0 comments on commit 618f885

Please sign in to comment.