Skip to content

Commit

Permalink
do not publish GRID_CELL_EDIT_PROPS_CHANGE_COMMITTED if there is an e…
Browse files Browse the repository at this point in the history
…rror
  • Loading branch information
m4theushw committed Jul 7, 2021
1 parent 069d382 commit ed7d333
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 28 deletions.
2 changes: 1 addition & 1 deletion docs/pages/api-docs/data-grid/grid-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { GridApi } from '@material-ui/x-grid';
| <span class="prop-name">applyFilterLinkOperator</span> | <span class="prop-type">(operator: GridLinkOperator) =&gt; void</span> | Changes the GridLinkOperator used to connect the filters. |
| <span class="prop-name">applyFilters</span> | <span class="prop-type">() =&gt; void</span> | Applies all filters on all rows. |
| <span class="prop-name">applySorting</span> | <span class="prop-type">() =&gt; void</span> | Applies the current sort model to the rows. |
| <span class="prop-name">commitCellChange</span> | <span class="prop-type">(params: GridCommitCellChangeParams) =&gt; void</span> | Updates the field at the given id with the value stored in the edit row model. |
| <span class="prop-name">commitCellChange</span> | <span class="prop-type">(params: GridCommitCellChangeParams, event?: SyntheticEvent&lt;Element, Event&gt;) =&gt; boolean</span> | Updates the field at the given id with the value stored in the edit row model. |
| <span class="prop-name">components</span> | <span class="prop-type">GridApiRefComponentsProperty</span> | The set of overridable components used in the grid. |
| <span class="prop-name optional">componentsProps<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">GridSlotsComponentsProps</span> | Overrideable components props dynamically passed to the component at rendering. |
| <span class="prop-name">deleteFilter</span> | <span class="prop-type">(item: GridFilterItem) =&gt; void</span> | Deletes a GridFilterItem. |
Expand Down
61 changes: 35 additions & 26 deletions packages/grid/_modules_/grid/hooks/features/rows/useGridEditRows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,7 @@ export function useGridEditRows(apiRef: GridApiRef) {
if (params.cellMode === 'view') {
return;
}

const cellCommitParams = apiRef.current.getEditCellPropsParams(params.id, params.field);
if (!cellCommitParams.props.error) {
// We commit the change when there is no error
apiRef.current.publishEvent(GRID_CELL_EDIT_PROPS_CHANGE_COMMITTED, cellCommitParams);
}

apiRef.current.commitCellChange(params);
apiRef.current.publishEvent(GRID_CELL_EDIT_EXIT, params);
};

Expand All @@ -67,7 +61,6 @@ export function useGridEditRows(apiRef: GridApiRef) {
if (event && (event as any).defaultMuiPrevented) {
return;
}

commitPropsAndExit(params);
},
);
Expand Down Expand Up @@ -138,13 +131,18 @@ export function useGridEditRows(apiRef: GridApiRef) {
);

const setEditCellProps = React.useCallback(
(params: GridEditCellPropsParams, event?: React.SyntheticEvent) => {
apiRef.current.publishEvent(GRID_CELL_EDIT_PROPS_CHANGE, params, event);
},
[apiRef],
);

const handleCellEditCellProps = React.useCallback(
(params: GridEditCellPropsParams, event?: React.SyntheticEvent) => {
if (event?.isPropagationStopped()) {
return;
}

apiRef.current.publishEvent(GRID_CELL_EDIT_PROPS_CHANGE, params, event);

const { id, field, props } = params;
logger.debug(`Setting cell props on id: ${id} field: ${field}`);
setGridState((state) => {
Expand Down Expand Up @@ -195,22 +193,32 @@ export function useGridEditRows(apiRef: GridApiRef) {
);

const commitCellChange = React.useCallback(
(params: GridCommitCellChangeParams, event?: React.SyntheticEvent) => {
if (event?.isPropagationStopped()) {
return;
}

(params: GridCommitCellChangeParams, event?: React.SyntheticEvent): boolean => {
const { id, field } = params;
const model = apiRef.current.getEditRowsModel();
if (!model[id] || !model[id][field]) {
throw new Error(`Cell at id: ${id} and field: ${field} is not in edit mode`);
}

const { value, error } = model[id][field];
if (error) {
const { error } = model[id][field];
if (!error) {
apiRef.current.publishEvent(GRID_CELL_EDIT_PROPS_CHANGE_COMMITTED, params, event);
return true;
}
return false;
},
[apiRef],
);

const handleCellEditPropsChangeCommited = React.useCallback(
(params: GridCommitCellChangeParams, event?: React.SyntheticEvent) => {
if (event?.isPropagationStopped()) {
return;
}

const { id, field } = params;
const model = apiRef.current.getEditRowsModel();
const { value } = model[id][field];
logger.debug(`Setting cell id: ${id} field: ${field} to value: ${value?.toString()}`);
const row = apiRef.current.getRow(id);
const rowUpdate = { ...row, [field]: value };
Expand Down Expand Up @@ -282,20 +290,16 @@ export function useGridEditRows(apiRef: GridApiRef) {
apiRef.current.publishEvent(GRID_CELL_EDIT_ENTER, params, event);
}
if (!isEditMode && isDeleteKeys(event.key)) {
const commitParams: GridEditCellPropsParams = apiRef.current.getEditCellPropsParams(
params.id,
params.field,
);
const commitParams = apiRef.current.getEditCellPropsParams(params.id, params.field);
commitParams.props.value = '';
apiRef.current.publishEvent(GRID_CELL_EDIT_PROPS_CHANGE_COMMITTED, commitParams, event);
apiRef.current.commitCellChange(commitParams, event);
apiRef.current.publishEvent(GRID_CELL_EDIT_EXIT, params, event);
}
if (isEditMode && isCellEditCommitKeys(event.key)) {
const cellCommitParams = apiRef.current.getEditCellPropsParams(params.id, params.field);
if (cellCommitParams.props.error) {
const commitParams = apiRef.current.getEditCellPropsParams(params.id, params.field);
if (!apiRef.current.commitCellChange(commitParams, event)) {
return;
}
apiRef.current.publishEvent(GRID_CELL_EDIT_PROPS_CHANGE_COMMITTED, cellCommitParams, event);
}
if (isEditMode && !event.isPropagationStopped() && isCellExitEditModeKeys(event.key)) {
apiRef.current.publishEvent(GRID_CELL_EDIT_EXIT, params, event);
Expand All @@ -317,8 +321,13 @@ export function useGridEditRows(apiRef: GridApiRef) {
useGridApiEventHandler(apiRef, GRID_CELL_EDIT_ENTER, handleEnterEdit);
useGridApiEventHandler(apiRef, GRID_CELL_EDIT_EXIT, handleExitEdit);
useGridApiEventHandler(apiRef, GRID_CELL_FOCUS_OUT, handleCellFocusOut);
useGridApiEventHandler(apiRef, GRID_CELL_EDIT_PROPS_CHANGE, handleCellEditCellProps);
useGridApiEventHandler(apiRef, GRID_COLUMN_HEADER_DRAG_START, handleColumnHeaderDragStart);
useGridApiEventHandler(apiRef, GRID_CELL_EDIT_PROPS_CHANGE_COMMITTED, commitCellChange);
useGridApiEventHandler(
apiRef,
GRID_CELL_EDIT_PROPS_CHANGE_COMMITTED,
handleCellEditPropsChangeCommited,
);

useGridApiOptionHandler(
apiRef,
Expand Down
4 changes: 3 additions & 1 deletion packages/grid/_modules_/grid/models/api/gridEditRowApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export interface GridEditRowApi {
/**
* Updates the field at the given id with the value stored in the edit row model.
* @param {GridCommitCellChangeParams} params The id and field to commit to.
* @param {React.SyntheticEvent} event The event to pass forward.
* @returns {boolean} A boolean indicating if there is an error.
*/
commitCellChange: (params: GridCommitCellChangeParams) => void;
commitCellChange: (params: GridCommitCellChangeParams, event?: React.SyntheticEvent) => boolean;
}
47 changes: 47 additions & 0 deletions packages/grid/x-grid/src/tests/editRows.XGrid.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -653,4 +653,51 @@ describe('<XGrid /> - Edit Rows', () => {
expect(onEditCellChange.args[0][0].props.value).to.equal(null);
});
});

describe('validation', () => {
it('should not allow to save an invalid value with Enter', () => {
const { setProps } = render(<TestCase editRowsModel={{}} />);
const cell = getCell(1, 0);
cell.focus();
fireEvent.doubleClick(cell);
const input = cell.querySelector('input')!;
expect(input).not.to.have.attribute('aria-invalid');
fireEvent.change(input, { target: { value: 'n' } });
setProps({ editRowsModel: { 1: { brand: { error: true, value: 'n' } } } });
fireEvent.keyDown(input, { key: 'Enter' });
expect(input).to.have.attribute('aria-invalid', 'true');
expect(cell).to.have.class('MuiDataGrid-cell--editing');
});

it('should not allow to save an invalid value with commitCellChange', () => {
const { setProps } = render(<TestCase editRowsModel={{}} />);
const cell = getCell(1, 0);
cell.focus();
fireEvent.doubleClick(cell);
const input = cell.querySelector('input')!;
expect(input).not.to.have.attribute('aria-invalid');
fireEvent.change(input, { target: { value: 'n' } });
setProps({ editRowsModel: { 1: { brand: { error: true, value: 'n' } } } });
apiRef.current.commitCellChange({ id: 1, field: 'brand' });
apiRef.current.setCellMode(1, 'brand', 'view');
expect(cell).to.have.text('Adidas');
});

it('should not call onEditCellChangeCommitted for invalid values', () => {
const onEditCellChangeCommitted = spy();
const { setProps } = render(
<TestCase onEditCellChangeCommitted={onEditCellChangeCommitted} editRowsModel={{}} />,
);
const cell = getCell(1, 0);
cell.focus();
fireEvent.doubleClick(cell);
const input = cell.querySelector('input')!;
expect(input).not.to.have.attribute('aria-invalid');
fireEvent.change(input, { target: { value: 'n' } });
setProps({ editRowsModel: { 1: { brand: { error: true, value: 'n' } } } });
apiRef.current.commitCellChange({ id: 1, field: 'brand' });
apiRef.current.setCellMode(1, 'brand', 'view');
expect(onEditCellChangeCommitted.callCount).to.equal(0);
});
});
});

0 comments on commit ed7d333

Please sign in to comment.