Skip to content

Commit

Permalink
e2e example on str and number
Browse files Browse the repository at this point in the history
  • Loading branch information
dtassone committed Feb 19, 2021
1 parent 2276f0a commit c13091c
Show file tree
Hide file tree
Showing 15 changed files with 277 additions and 130 deletions.
2 changes: 1 addition & 1 deletion packages/grid/_modules_/grid/components/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const Cell: React.FC<GridCellProps> = React.memo((props) => {
ref={cellRef}
className={classnames(CELL_CSS_CLASS, cssClass, `MuiDataGrid-cell${capitalize(align)}`, {
'MuiDataGrid-withBorder': showRightBorder,
'MuiDataGrid-editable': isEditable
'MuiDataGrid-cellEditable': isEditable,
})}
role="cell"
data-value={value}
Expand Down
4 changes: 2 additions & 2 deletions packages/grid/_modules_/grid/components/RowCells.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ export const RowCells: React.FC<RowCellsProps> = React.memo((props) => {
cssClassProp = { cssClass: `${cssClassProp.cssClass} MuiDataGrid-cellWithRenderer` };
}
if (editCellState && column.renderEditCell) {
const params = editCellState === true ? cellParams : {...cellParams, ...editCellState};
const params = editCellState === true ? cellParams : { ...cellParams, ...editCellState };
cellComponent = column.renderEditCell(params);
cssClassProp = { cssClass: `${cssClassProp.cssClass} MuiDataGrid-cellEdit` };
cssClassProp = { cssClass: `${cssClassProp.cssClass} MuiDataGrid-cellEditing` };
}

const cellProps: GridCellProps & { children: any } = {
Expand Down
84 changes: 60 additions & 24 deletions packages/grid/_modules_/grid/components/editCell/StringEditCell.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,91 @@
import * as React from 'react';
import TextField from '@material-ui/core/TextField';
import TextField, { TextFieldProps } from '@material-ui/core/TextField';
import { CellParams } from '../../models/params/cellParams';
import { isDate } from '../../utils/utils';

export interface StringEditCellProps extends CellParams {
isValid?: boolean;
// export interface StringEditCellProps extends CellParams {
// isValid?: boolean;
// }
function mapColDefTypeToInputType(type: string) {
switch (type) {
case 'string':
return 'text';
case 'number':
case 'date':
return type;
case 'dateTime':
return 'datetime-local';
default:
return 'text';
}
}

export function StringEditCell(props: StringEditCellProps) {
const { value, api, field, row, isValid } = props;
export function StringEditCell(props: CellParams & TextFieldProps) {
const {
value,
api,
field,
row,
colDef,
getValue,
rowIndex,
colIndex,
isEditable,
...textFieldProps
} = props;
const [inputValueState, setInputValueState] = React.useState(value || '');

const onValueChange = React.useCallback((event) => {
const newValue = event.target.value;
//TODO consider removing local state, and just use gridState
setInputValueState(newValue);
const onValueChange = React.useCallback(
(event) => {
const newValue = event.target.value;
//TODO consider removing local state, and just use gridState
setInputValueState(newValue);

const update = { id: row.id };
update[field] = newValue;
api.setEditCellValue(update);
}, [api, field, row.id]);
const update = { id: row.id };
update[field] = newValue;
api.setEditCellValue(update);
},
[api, field, row.id],
);

const onKeyDown = React.useCallback(
(event: React.KeyboardEvent) => {
if (event.key === 'Enter') {
if (!textFieldProps.error && event.key === 'Enter') {
const update = { id: row.id };
update[field] = inputValueState;
api.commitCellValueChanges(update)
api.commitCellValueChanges(update);
}

if (event.key === 'Escape' || event.key === 'Enter') {
if (event.key === 'Escape') {
api.setCellMode(row.id, field, 'view');
}
},
[api, field, inputValueState, row.id],
[api, field, inputValueState, textFieldProps, row.id],
);

React.useEffect(() => {
setInputValueState(value || '');

}, [value]);

const inputType = mapColDefTypeToInputType(colDef.type);
let formattedValue = inputValueState;
if (isDate(value)) {
//TODO fix issue with local date as 00:00 time returns -1 day
formattedValue = value.toISOString().substr(0, colDef.type === 'dateTime' ? 16 : 10);
}

return (
<TextField
onKeyDown={onKeyDown}
label={'Value'}
placeholder={'Filter value'}
value={inputValueState}
label={field}
placeholder={'Edit value'}
value={formattedValue}
onChange={onValueChange}
type="text"
type={inputType}
variant="standard"
error={isValid===false}
InputLabelProps={{
shrink: true,
}}
{...textFieldProps}
/>
);
}
Expand Down
1 change: 1 addition & 0 deletions packages/grid/_modules_/grid/constants/eventsConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const DRAGEND = 'dragend';
export const CELL_VALUE_CHANGE = 'cellValueChange';
export const CELL_VALUE_CHANGE_COMMITTED = 'cellValueChangeCommitted';
export const CELL_MODE_CHANGE = 'cellModeChange';
export const EDIT_ROW_MODEL_CHANGE = 'editRowModelChange';
export const COMPONENT_ERROR = 'componentError';
export const UNMOUNT = 'unmount';
export const GRID_FOCUS_OUT = 'gridFocusOut';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const DEFAULT_LOCALE_TEXT: LocaleText = {
filterOperatorEndsWith: 'ends with',
filterOperatorIs: 'is',
filterOperatorNot: 'is not',
filterOperatorAfter: 'is after',
filterOperatorOnOrAfter: 'is on or after',
filterOperatorBefore: 'is before',
filterOperatorOnOrBefore: 'is on or before',
Expand Down
116 changes: 75 additions & 41 deletions packages/grid/_modules_/grid/hooks/features/rows/useEditRows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
CELL_MODE_CHANGE,
CELL_VALUE_CHANGE,
CELL_VALUE_CHANGE_COMMITTED,
EDIT_ROW_MODEL_CHANGE,
} from '../../../constants/eventsConstants';
import { ApiRef } from '../../../models/api/apiRef';
import { EditRowApi } from '../../../models/api/rowApi';
Expand Down Expand Up @@ -30,23 +31,33 @@ export function useEditRows(apiRef: ApiRef) {
const [, setGridState, forceUpdate] = useGridState(apiRef);
const options = useGridSelector(apiRef, optionsSelector);

const setCellEditMode = React.useCallback((id, field)=> {
setGridState((state) => {
const currentCellEditState: EditRowsModel = {};
currentCellEditState[id] = {};
currentCellEditState[id][field] = true;
const setCellEditMode = React.useCallback(
(id, field) => {
setGridState((state) => {
const currentCellEditState: EditRowsModel = { ...state.editRows };
currentCellEditState[id] = currentCellEditState[id] || {};
currentCellEditState[id][field] = true;

const newEditRowsState = { ...state.editRows, ...currentCellEditState };
const newEditRowsState = { ...state.editRows, ...currentCellEditState };

return { ...state, editRows: newEditRowsState };
});
forceUpdate();
}, [forceUpdate, setGridState])
apiRef.current.publishEvent(EDIT_ROW_MODEL_CHANGE, newEditRowsState);
return { ...state, editRows: newEditRowsState };
});
apiRef.current.publishEvent(CELL_MODE_CHANGE, {
id,
field,
mode: 'edit',
api: apiRef.current,
});
forceUpdate();
},
[apiRef, forceUpdate, setGridState],
);

const setCellViewMode = React.useCallback(
(id, field) => {
setGridState((state) => {
const newEditRowsState = { ...state.editRows };
const newEditRowsState: EditRowsModel = { ...state.editRows };

if (!newEditRowsState[id]) {
return state;
Expand All @@ -58,17 +69,24 @@ export function useEditRows(apiRef: ApiRef) {
delete newEditRowsState[id];
}
}
apiRef.current.publishEvent(EDIT_ROW_MODEL_CHANGE, newEditRowsState);

return { ...state, editRows: newEditRowsState };
});
apiRef.current.publishEvent(CELL_MODE_CHANGE, {
id,
field,
mode: 'view',
api: apiRef.current,
});
forceUpdate();
},
[forceUpdate, setGridState],
[apiRef, forceUpdate, setGridState],
);

const setCellMode = React.useCallback(
(id, field, mode: CellMode) => {
if(mode === 'edit') {
if (mode === 'edit') {
setCellEditMode(id, field);
} else {
setCellViewMode(id, field);
Expand All @@ -77,44 +95,60 @@ export function useEditRows(apiRef: ApiRef) {
[setCellEditMode, setCellViewMode],
);

const isCellEditable = React.useCallback((params: CellParams)=> {
if(!options.isCellEditable) {
return params.colDef.editable;
}
return options.isCellEditable(params);

}, [options.isCellEditable]);

const commitCellValueChanges = React.useCallback((update: RowModelUpdate)=> {
apiRef.current.publishEvent(CELL_VALUE_CHANGE_COMMITTED, {update, api: apiRef.current})
//TODO don't update when it's in server mode
//How should we turn server mode? featureMode === 'server' ?

apiRef.current.updateRows([update]);
}, [apiRef]);
const isCellEditable = React.useCallback(
(params: CellParams) => {
return params.colDef.editable && (!options.isCellEditable || options.isCellEditable(params));
},
[options.isCellEditable],
);

const setEditCellValue = React.useCallback((update: RowModelUpdate)=> {
apiRef.current.publishEvent(CELL_VALUE_CHANGE, {update, api: apiRef.current})
const commitCellValueChanges = React.useCallback(
(update: RowModelUpdate) => {
if (apiRef.current.hasListener(CELL_VALUE_CHANGE_COMMITTED)) {
apiRef.current.publishEvent(CELL_VALUE_CHANGE_COMMITTED, { update, api: apiRef.current });
return;
}
//TODO don't update when it's in server mode
//How should we turn server mode? featureMode === 'server' ?

}, [apiRef]);
apiRef.current.updateRows([update]);
const field = Object.keys(update).find((key) => key !== 'id')!;
apiRef.current.setCellMode(update.id, field, 'view');
},
[apiRef],
);

const setEditRowsModel = React.useCallback((editRows: EditRowsModel)=> {
setGridState(state=> {
const newState = {...state, editRows };
return newState;
})
forceUpdate();
const setEditCellValue = React.useCallback(
(update: RowModelUpdate) => {
apiRef.current.publishEvent(CELL_VALUE_CHANGE, { update, api: apiRef.current });
},
[apiRef],
);

}, [forceUpdate, setGridState])
const setEditRowsModel = React.useCallback(
(editRows: EditRowsModel) => {
setGridState((state) => {
const newState = { ...state, editRows };
return newState;
});
forceUpdate();
},
[forceUpdate, setGridState],
);

//TODO add those options.handlers on apiRef
useApiEventHandler(apiRef, CELL_VALUE_CHANGE, options.onEditCellValueChange);
useApiEventHandler(apiRef, CELL_VALUE_CHANGE_COMMITTED, options.onEditCellValueChangeCommitted);
useApiEventHandler(apiRef, CELL_MODE_CHANGE, options.onCellModeChange);
useApiEventHandler(apiRef, EDIT_ROW_MODEL_CHANGE, options.onEditRowModelChange);

useApiMethod<EditRowApi>(apiRef, { setCellMode, isCellEditable, commitCellValueChanges, setEditCellValue, setEditRowsModel}, 'EditRowApi');
useApiMethod<EditRowApi>(
apiRef,
{ setCellMode, isCellEditable, commitCellValueChanges, setEditCellValue, setEditRowsModel },
'EditRowApi',
);

React.useEffect(()=> {
React.useEffect(() => {
apiRef.current.setEditRowsModel(options.editRowsModel || {});
}, [apiRef, forceUpdate, options.editRowsModel])
}, [apiRef, forceUpdate, options.editRowsModel]);
}
5 changes: 4 additions & 1 deletion packages/grid/_modules_/grid/hooks/root/useEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ import {
FOCUS_OUT,
GRID_FOCUS_OUT,
COMPONENT_ERROR,
STATE_CHANGE, DOUBLE_CELL_CLICK, DOUBLE_ROW_CLICK, DOUBLE_CLICK,
STATE_CHANGE,
DOUBLE_CELL_CLICK,
DOUBLE_ROW_CLICK,
DOUBLE_CLICK,
} from '../../constants/eventsConstants';
import { CELL_CSS_CLASS, ROW_CSS_CLASS } from '../../constants/cssClassesConstants';
import { findParentElementFromClassName, getIdFromRowElem, isCell } from '../../utils/domUtils';
Expand Down
1 change: 1 addition & 0 deletions packages/grid/_modules_/grid/locales/bgBG.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const bgBG: Localization = getLocalization({
filterOperatorIs: 'е',
filterOperatorNot: 'не е',
filterOperatorOnOrAfter: 'е на или след',
filterOperatorAfter: 'е след',
filterOperatorBefore: 'е преди',
filterOperatorOnOrBefore: 'е на или преди',

Expand Down
1 change: 1 addition & 0 deletions packages/grid/_modules_/grid/models/api/localeTextApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface LocaleText {
filterOperatorEndsWith: string;
filterOperatorIs: string;
filterOperatorNot: string;
filterOperatorAfter: string;
filterOperatorOnOrAfter: string;
filterOperatorBefore: string;
filterOperatorOnOrBefore: string;
Expand Down
6 changes: 3 additions & 3 deletions packages/grid/_modules_/grid/models/api/rowApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export interface RowApi {
export interface EditRowApi {
setEditRowsModel: (model: EditRowsModel) => void;
setCellMode: (rowId: RowId, field: string, mode: CellMode) => void;
isCellEditable: (params: CellParams)=> boolean;
setEditCellValue: (update: RowModelUpdate)=> void;
commitCellValueChanges: (update: RowModelUpdate)=> void;
isCellEditable: (params: CellParams) => boolean;
setEditCellValue: (update: RowModelUpdate) => void;
commitCellValueChanges: (update: RowModelUpdate) => void;
}
2 changes: 2 additions & 0 deletions packages/grid/_modules_/grid/models/colDef/numericColDef.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { renderEditStringCell } from '../../components/editCell/StringEditCell';
import { numberComparer } from '../../utils/sortingUtils';
import { isNumber } from '../../utils/utils';
import { getNumericColumnOperators } from './numericOperators';
Expand All @@ -12,4 +13,5 @@ export const NUMERIC_COL_DEF: ColTypeDef = {
sortComparator: numberComparer,
valueFormatter: ({ value }) => (value && isNumber(value) && value.toLocaleString()) || value,
filterOperators: getNumericColumnOperators(),
renderEditCell: renderEditStringCell,
};
10 changes: 6 additions & 4 deletions packages/grid/_modules_/grid/models/gridOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,12 @@ export interface GridOptions {
/**
* Callback fired when the cell is rendered.
*/
isCellEditable?: (params: CellParams)=> boolean;
onCellModeChange?: ()=> void;
onEditCellValueChange?: (params: {api: any, update: RowModelUpdate })=> void;
onEditCellValueChangeCommitted?: (params: {api: any, update: RowModelUpdate })=> void;
isCellEditable?: (params: CellParams) => boolean;
onCellModeChange?: ({ id: RowId, field: string, api: any, mode: CellMode }) => void;
onEditCellValueChange?: (params: { api: any; update: RowModelUpdate }) => void;
onEditCellValueChangeCommitted?: (params: { api: any; update: RowModelUpdate }) => void;
onEditRowModelChange?: (model: EditRowsModel) => void;

/**
* Extend native column types with your new column types.
*/
Expand Down
4 changes: 4 additions & 0 deletions packages/grid/_modules_/grid/utils/EventEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export class EventEmitter {

events: { [key: string]: Listener[] } = {};

hasListener(eventName: string): boolean {
return this.events[eventName].length > 0;
}

on(eventName: string, listener: Listener): void {
if (!Array.isArray(this.events[eventName])) {
this.events[eventName] = [];
Expand Down
Loading

0 comments on commit c13091c

Please sign in to comment.