Skip to content

Commit 33b6863

Browse files
authored
[DataGrid] Add single select column type (#1956)
1 parent db033be commit 33b6863

23 files changed

+684
-512
lines changed

docs/pages/api-docs/data-grid/grid-col-def.md

+28-27
Large diffs are not rendered by default.

docs/src/pages/components/data-grid/columns/ColumnTypesGrid.js

+16
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const rows = [
1313
dateCreated: randomCreatedDate(),
1414
lastLogin: randomUpdatedDate(),
1515
isAdmin: true,
16+
country: 'Spain',
1617
},
1718
{
1819
id: 2,
@@ -21,6 +22,7 @@ const rows = [
2122
dateCreated: randomCreatedDate(),
2223
lastLogin: randomUpdatedDate(),
2324
isAdmin: true,
25+
country: 'France',
2426
},
2527
{
2628
id: 3,
@@ -29,6 +31,7 @@ const rows = [
2931
dateCreated: randomCreatedDate(),
3032
lastLogin: randomUpdatedDate(),
3133
isAdmin: false,
34+
country: 'Brazil',
3235
},
3336
];
3437

@@ -42,6 +45,19 @@ export default function ColumnTypesGrid() {
4245
{ field: 'dateCreated', type: 'date', width: 130 },
4346
{ field: 'lastLogin', type: 'dateTime', width: 180 },
4447
{ field: 'isAdmin', type: 'boolean', width: 120 },
48+
{
49+
field: 'country',
50+
type: 'singleSelect',
51+
width: 150,
52+
valueOptions: [
53+
'Bulgaria',
54+
'Netherlands',
55+
'France',
56+
'United Kingdom',
57+
'Spain',
58+
'Brazil',
59+
],
60+
},
4561
]}
4662
rows={rows}
4763
/>

docs/src/pages/components/data-grid/columns/ColumnTypesGrid.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const rows = [
1313
dateCreated: randomCreatedDate(),
1414
lastLogin: randomUpdatedDate(),
1515
isAdmin: true,
16+
country: 'Spain',
1617
},
1718
{
1819
id: 2,
@@ -21,6 +22,7 @@ const rows = [
2122
dateCreated: randomCreatedDate(),
2223
lastLogin: randomUpdatedDate(),
2324
isAdmin: true,
25+
country: 'France',
2426
},
2527
{
2628
id: 3,
@@ -29,6 +31,7 @@ const rows = [
2931
dateCreated: randomCreatedDate(),
3032
lastLogin: randomUpdatedDate(),
3133
isAdmin: false,
34+
country: 'Brazil',
3235
},
3336
];
3437

@@ -42,6 +45,19 @@ export default function ColumnTypesGrid() {
4245
{ field: 'dateCreated', type: 'date', width: 130 },
4346
{ field: 'lastLogin', type: 'dateTime', width: 180 },
4447
{ field: 'isAdmin', type: 'boolean', width: 120 },
48+
{
49+
field: 'country',
50+
type: 'singleSelect',
51+
width: 150,
52+
valueOptions: [
53+
'Bulgaria',
54+
'Netherlands',
55+
'France',
56+
'United Kingdom',
57+
'Spain',
58+
'Brazil',
59+
],
60+
},
4561
]}
4662
rows={rows}
4763
/>

docs/src/pages/components/data-grid/columns/columns.md

+2
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,10 @@ The following are the native column types:
240240
- `'date'`
241241
- `'dateTime'`
242242
- `'boolean'`
243+
- `'singleSelect'`
243244

244245
To apply a column type, you need to define the type property in your column definition.
246+
If the column is `type: 'singleSelect'` you also need to set the `valueOptions` property in that column definition.
245247

246248
{{"demo": "pages/components/data-grid/columns/ColumnTypesGrid.js", "bg": "inline"}}
247249

docs/src/pages/components/data-grid/demo/FullFeaturedDemo.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ export default function FullFeaturedDemo() {
255255
const { loading, data, setRowLength, loadNewData } = useDemoData({
256256
dataSet: type,
257257
rowLength: size,
258-
maxColumns: 20,
258+
maxColumns: 40,
259259
editable: true,
260260
});
261261

docs/src/pages/components/data-grid/demo/FullFeaturedDemo.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ export default function FullFeaturedDemo() {
271271
const { loading, data, setRowLength, loadNewData } = useDemoData({
272272
dataSet: type,
273273
rowLength: size,
274-
maxColumns: 20,
274+
maxColumns: 40,
275275
editable: true,
276276
});
277277

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import * as React from 'react';
2+
import Select, { SelectProps } from '@material-ui/core/Select';
3+
import MenuItem from '@material-ui/core/MenuItem';
4+
import { GridCellParams } from '../../models/params/gridCellParams';
5+
import { isEscapeKey } from '../../utils/keyboardUtils';
6+
7+
const renderSingleSelectOptions = (option) =>
8+
typeof option === 'string' ? (
9+
<MenuItem key={option} value={option}>
10+
{option}
11+
</MenuItem>
12+
) : (
13+
<MenuItem key={option.value} value={option.value}>
14+
{option.label}
15+
</MenuItem>
16+
);
17+
18+
export function GridEditSingleSelectCell(props: GridCellParams & SelectProps) {
19+
const {
20+
id,
21+
value,
22+
formattedValue,
23+
api,
24+
field,
25+
row,
26+
colDef,
27+
cellMode,
28+
isEditable,
29+
className,
30+
getValue,
31+
hasFocus,
32+
...other
33+
} = props;
34+
35+
const handleChange = (event) => {
36+
const editProps = { value: event.target.value };
37+
38+
if (event.key) {
39+
api.setEditCellProps({ id, field, props: editProps }, event);
40+
} else {
41+
api.commitCellChange({ id, field, props: editProps }, event);
42+
api.setCellMode(id, field, 'view');
43+
}
44+
};
45+
46+
const handleClose = (event, reason) => {
47+
if (reason === 'backdropClick' || isEscapeKey(event.key)) {
48+
api.setCellMode(id, field, 'view');
49+
}
50+
};
51+
52+
return (
53+
<Select
54+
value={value}
55+
onChange={handleChange}
56+
MenuProps={{
57+
onClose: handleClose,
58+
}}
59+
autoFocus
60+
fullWidth
61+
open
62+
{...other}
63+
>
64+
{colDef.valueOptions.map(renderSingleSelectOptions)}
65+
</Select>
66+
);
67+
}
68+
export const renderEditSingleSelectCell = (params) => <GridEditSingleSelectCell {...params} />;

packages/grid/_modules_/grid/components/panel/filterPanel/GridFilterInputValue.tsx

+26-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,25 @@ import TextField, { TextFieldProps } from '@material-ui/core/TextField';
44
import { unstable_useId as useId } from '@material-ui/core/utils';
55
import { GridLoadIcon } from '../../icons/index';
66
import { GridFilterInputValueProps } from './GridFilterInputValueProps';
7+
import { GridColDef } from '../../../models/colDef/gridColDef';
8+
9+
const renderSingleSelectOptions = ({ valueOptions }: GridColDef) =>
10+
['', ...valueOptions!].map((option) =>
11+
typeof option === 'string' ? (
12+
<option key={option} value={option}>
13+
{option}
14+
</option>
15+
) : (
16+
<option key={option.value} value={option.value}>
17+
{option.label}
18+
</option>
19+
),
20+
);
721

822
export const SUBMIT_FILTER_STROKE_TIME = 500;
923

1024
export interface GridTypeFilterInputValueProps extends GridFilterInputValueProps {
11-
type?: 'text' | 'number' | 'date' | 'datetime-local';
25+
type?: 'text' | 'number' | 'date' | 'datetime-local' | 'singleSelect';
1226
}
1327

1428
export function GridFilterInputValue(props: GridTypeFilterInputValueProps & TextFieldProps) {
@@ -17,6 +31,16 @@ export function GridFilterInputValue(props: GridTypeFilterInputValueProps & Text
1731
const [filterValueState, setFilterValueState] = React.useState(item.value || '');
1832
const [applying, setIsApplying] = React.useState(false);
1933
const id = useId();
34+
const singleSelectProps: TextFieldProps =
35+
type === 'singleSelect'
36+
? {
37+
select: true,
38+
SelectProps: {
39+
native: true,
40+
},
41+
children: renderSingleSelectOptions(apiRef.current.getColumn(item.columnField)),
42+
}
43+
: {};
2044

2145
const onFilterChange = React.useCallback(
2246
(event) => {
@@ -57,6 +81,7 @@ export function GridFilterInputValue(props: GridTypeFilterInputValueProps & Text
5781
InputLabelProps={{
5882
shrink: true,
5983
}}
84+
{...singleSelectProps}
6085
{...others}
6186
/>
6287
);

packages/grid/_modules_/grid/models/colDef/gridColDef.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export interface GridColDef {
5959
resizable?: boolean;
6060
/**
6161
* If `true`, the cells of the column are editable.
62-
* @default true
62+
* @default false
6363
*/
6464
editable?: boolean;
6565
/**
@@ -71,6 +71,10 @@ export interface GridColDef {
7171
* @default 'string'
7272
*/
7373
type?: GridColType;
74+
/**
75+
* To be used in combination with `type: 'singleSelect'`. This is an array of the possible cell values and labels.
76+
*/
77+
valueOptions?: Array<string | { value: any; label: string }>;
7478
/**
7579
* Allows to align the column values in cells.
7680
*/

packages/grid/_modules_/grid/models/colDef/gridColType.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,11 @@ export const GRID_DATE_COLUMN_TYPE = 'date';
44
export const GRID_DATETIME_COLUMN_TYPE = 'dateTime';
55
export const GRID_BOOLEAN_COLUMN_TYPE = 'boolean';
66

7-
export type GridNativeColTypes = 'string' | 'number' | 'date' | 'dateTime' | 'boolean';
7+
export type GridNativeColTypes =
8+
| 'string'
9+
| 'number'
10+
| 'date'
11+
| 'dateTime'
12+
| 'boolean'
13+
| 'singleSelect';
814
export type GridColType = GridNativeColTypes | string;

packages/grid/_modules_/grid/models/colDef/gridDefaultColumnTypes.ts

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { GRID_STRING_COL_DEF } from './gridStringColDef';
33
import { GRID_NUMERIC_COL_DEF } from './gridNumericColDef';
44
import { GRID_DATE_COL_DEF, GRID_DATETIME_COL_DEF } from './gridDateColDef';
55
import { GRID_BOOLEAN_COL_DEF } from './gridBooleanColDef';
6+
import { GRID_SINGLE_SELECT_COL_DEF } from './gridSingleSelectColDef';
67

78
export const DEFAULT_GRID_COL_TYPE_KEY = '__default__';
89
export const getGridDefaultColumnTypes: () => GridColumnTypesRecord = () => {
@@ -12,6 +13,7 @@ export const getGridDefaultColumnTypes: () => GridColumnTypesRecord = () => {
1213
date: GRID_DATE_COL_DEF,
1314
dateTime: GRID_DATETIME_COL_DEF,
1415
boolean: GRID_BOOLEAN_COL_DEF,
16+
singleSelect: GRID_SINGLE_SELECT_COL_DEF,
1517
};
1618
nativeColumnTypes[DEFAULT_GRID_COL_TYPE_KEY] = GRID_STRING_COL_DEF;
1719

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { GRID_STRING_COL_DEF } from './gridStringColDef';
2+
import { GridColTypeDef } from './gridColDef';
3+
import { renderEditSingleSelectCell } from '../../components/cell/GridEditSingleSelectCell';
4+
import { getGridSingleSelectOperators } from './gridSingleSelectOperators';
5+
6+
export const GRID_SINGLE_SELECT_COL_DEF: GridColTypeDef = {
7+
...GRID_STRING_COL_DEF,
8+
type: 'singleSelect',
9+
renderEditCell: renderEditSingleSelectCell,
10+
filterOperators: getGridSingleSelectOperators(),
11+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { GridFilterInputValue } from '../../components/panel/filterPanel/GridFilterInputValue';
2+
import { GridFilterItem } from '../gridFilterItem';
3+
import { GridFilterOperator } from '../gridFilterOperator';
4+
5+
export const getGridSingleSelectOperators: () => GridFilterOperator[] = () => [
6+
{
7+
value: 'is',
8+
getApplyFilterFn: (filterItem: GridFilterItem) => {
9+
if (!filterItem.columnField || !filterItem.value || !filterItem.operatorValue) {
10+
return null;
11+
}
12+
return ({ value }): boolean => {
13+
return typeof value === 'string'
14+
? filterItem.value === value
15+
: filterItem.value === (value as { value: any; label: string }).value;
16+
};
17+
},
18+
InputComponent: GridFilterInputValue,
19+
InputComponentProps: { type: 'singleSelect' },
20+
},
21+
{
22+
value: 'not',
23+
getApplyFilterFn: (filterItem: GridFilterItem) => {
24+
if (!filterItem.columnField || !filterItem.value || !filterItem.operatorValue) {
25+
return null;
26+
}
27+
28+
return ({ value }): boolean => {
29+
return typeof value === 'string'
30+
? filterItem.value !== value
31+
: filterItem.value !== (value as { value: any; label: string }).value;
32+
};
33+
},
34+
InputComponent: GridFilterInputValue,
35+
InputComponentProps: { type: 'singleSelect' },
36+
},
37+
];

0 commit comments

Comments
 (0)