Skip to content

Commit 27877b7

Browse files
DataGrid: make showEditorAlways cell editable in new row when allowUpdating false (T1323684) (#32902)
1 parent 970e4ad commit 27877b7

2 files changed

Lines changed: 191 additions & 12 deletions

File tree

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import DataGrid from 'devextreme-testcafe-models/dataGrid';
2+
import { GridsEditMode } from 'devextreme/ui/data_grid';
3+
import { createWidget } from '../../../../helpers/createWidget';
4+
import url from '../../../../helpers/getPageUrl';
5+
6+
fixture.disablePageReloads`Editing - showEditorAlways cell in new row should be editable (T1323684)`
7+
.page(url(__dirname, '../../../container.html'));
8+
9+
const READONLY_CLASS = 'dx-datagrid-readonly';
10+
const CELL_FOCUS_DISABLED_CLASS = 'dx-cell-focus-disabled';
11+
12+
(['cell', 'batch'] as GridsEditMode[]).forEach((mode) => {
13+
test(`showEditorAlways editor should be editable in a new row when allowUpdating is false, ${mode} mode`, async (t) => {
14+
const dataGrid = new DataGrid('#container');
15+
const addRowButton = dataGrid.getHeaderPanel().getAddRowButton();
16+
17+
await t.click(addRowButton);
18+
19+
const newRow = dataGrid.getDataRow(0);
20+
await t.expect(newRow.isInserted).ok();
21+
22+
const cell = dataGrid.getDataCell(0, 1);
23+
const editor = cell.getEditor();
24+
25+
await t
26+
.expect(cell.element.hasClass(READONLY_CLASS))
27+
.notOk('showEditorAlways cell in new row should not have readonly class')
28+
.expect(cell.element.hasClass(CELL_FOCUS_DISABLED_CLASS))
29+
.notOk('showEditorAlways cell in new row should not have cell-focus-disabled class');
30+
31+
await t
32+
.click(editor.element)
33+
.expect(cell.isFocused)
34+
.ok('showEditorAlways cell should be focused after click')
35+
.expect(editor.element.focused)
36+
.ok('editor should be focused after click')
37+
.typeText(editor.element, 'test value', { replace: true })
38+
.expect(editor.element.value)
39+
.eql('test value');
40+
}).before(async () => createWidget('dxDataGrid', {
41+
keyExpr: 'ID',
42+
dataSource: [
43+
{ ID: 1, FirstName: 'John', LastName: 'Heart' },
44+
{ ID: 2, FirstName: 'Olivia', LastName: 'Peyton' },
45+
],
46+
showBorders: true,
47+
editing: {
48+
mode,
49+
allowUpdating: false,
50+
allowAdding: true,
51+
},
52+
columns: [
53+
'LastName',
54+
{ dataField: 'FirstName', showEditorAlways: true },
55+
],
56+
}));
57+
58+
test(`Boolean editor should be editable in a new row when allowUpdating is false, ${mode} mode`, async (t) => {
59+
const dataGrid = new DataGrid('#container');
60+
const addRowButton = dataGrid.getHeaderPanel().getAddRowButton();
61+
62+
await t.click(addRowButton);
63+
64+
const newRow = dataGrid.getDataRow(0);
65+
await t.expect(newRow.isInserted).ok();
66+
67+
const booleanCell = dataGrid.getDataCell(0, 1);
68+
69+
await t
70+
.expect(booleanCell.element.hasClass(READONLY_CLASS))
71+
.notOk('boolean cell in new row should not have readonly class');
72+
73+
await t
74+
.click(booleanCell.element)
75+
.click(booleanCell.getCheckbox())
76+
.expect(booleanCell.getEditor().isChecked())
77+
.ok('checkbox in new row should be checked after click in it');
78+
}).before(async () => createWidget('dxDataGrid', {
79+
keyExpr: 'ID',
80+
dataSource: [
81+
{ ID: 1, Name: 'John', Active: false },
82+
{ ID: 2, Name: 'Olivia', Active: true },
83+
],
84+
showBorders: true,
85+
editing: {
86+
mode,
87+
allowUpdating: false,
88+
allowAdding: true,
89+
},
90+
columns: [
91+
'Name',
92+
{ dataField: 'Active', dataType: 'boolean' },
93+
],
94+
}));
95+
96+
test(`showEditorAlways editor in existing rows should remain readonly when allowUpdating is false, ${mode} mode`, async (t) => {
97+
const dataGrid = new DataGrid('#container');
98+
const existingCell = dataGrid.getDataCell(0, 1);
99+
100+
await t
101+
.expect(existingCell.element.hasClass(READONLY_CLASS))
102+
.ok('showEditorAlways cell in existing row should have readonly class when allowUpdating is false');
103+
104+
await t
105+
.click(existingCell.getEditor().element)
106+
.expect(existingCell.element.hasClass(READONLY_CLASS))
107+
.ok('showEditorAlways cell in existing row should remain readonly after click');
108+
}).before(async () => createWidget('dxDataGrid', {
109+
keyExpr: 'ID',
110+
dataSource: [
111+
{ ID: 1, FirstName: 'John', LastName: 'Heart' },
112+
{ ID: 2, FirstName: 'Olivia', LastName: 'Peyton' },
113+
],
114+
showBorders: true,
115+
editing: {
116+
mode,
117+
allowUpdating: false,
118+
allowAdding: true,
119+
},
120+
columns: [
121+
'LastName',
122+
{ dataField: 'FirstName', showEditorAlways: true },
123+
],
124+
}));
125+
});
126+
127+
test('showEditorAlways editor should be editable in a new row when allowUpdating is a function returning false, cell mode', async (t) => {
128+
const dataGrid = new DataGrid('#container');
129+
const addRowButton = dataGrid.getHeaderPanel().getAddRowButton();
130+
131+
await t.click(addRowButton);
132+
133+
const newRow = dataGrid.getDataRow(0);
134+
await t.expect(newRow.isInserted).ok();
135+
136+
const cell = dataGrid.getDataCell(0, 1);
137+
const editor = cell.getEditor();
138+
139+
await t
140+
.expect(cell.element.hasClass(READONLY_CLASS))
141+
.notOk('showEditorAlways cell in new row should not have readonly class')
142+
.expect(cell.element.hasClass(CELL_FOCUS_DISABLED_CLASS))
143+
.notOk('showEditorAlways cell in new row should not have cell-focus-disabled class');
144+
145+
await t
146+
.click(editor.element)
147+
.expect(cell.isFocused)
148+
.ok('showEditorAlways cell should be focused after click')
149+
.expect(editor.element.focused)
150+
.ok('editor should be focused after click')
151+
.typeText(editor.element, 'test value', { replace: true })
152+
.expect(editor.element.value)
153+
.eql('test value');
154+
}).before(async () => createWidget('dxDataGrid', {
155+
keyExpr: 'ID',
156+
dataSource: [
157+
{ ID: 1, FirstName: 'John', LastName: 'Heart' },
158+
{ ID: 2, FirstName: 'Olivia', LastName: 'Peyton' },
159+
],
160+
showBorders: true,
161+
editing: {
162+
mode: 'cell' as GridsEditMode,
163+
allowUpdating: () => false,
164+
allowAdding: true,
165+
},
166+
columns: [
167+
'LastName',
168+
{ dataField: 'FirstName', showEditorAlways: true },
169+
],
170+
}));

packages/devextreme/js/__internal/grids/grid_core/editing/m_editing.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ import * as iconUtils from '@js/core/utils/icon';
2222
import { each } from '@js/core/utils/iterator';
2323
import { deepExtendArraySafe } from '@js/core/utils/object';
2424
import {
25-
isDefined, isEmptyObject,
26-
isFunction, isObject,
25+
isDefined, isEmptyObject, isFunction, isObject,
2726
} from '@js/core/utils/type';
2827
import { confirm } from '@js/ui/dialog';
2928
import { current, isFluent } from '@js/ui/themes';
@@ -2254,23 +2253,33 @@ class EditingControllerImpl extends modules.ViewController {
22542253
}
22552254

22562255
public getColumnTemplate(options) {
2257-
const { column } = options;
2258-
const rowIndex = options.row && options.row.rowIndex;
2256+
const { column, row, rowType } = options;
2257+
const rowIndex = row?.rowIndex;
22592258
let template;
2259+
22602260
const isRowMode = this.isRowBasedEditMode();
22612261
const isRowEditing = this.isEditRow(rowIndex);
22622262
const isCellEditing = this.isEditCell(rowIndex, options.columnIndex);
2263-
let editingStartOptions;
22642263

2265-
if ((column.showEditorAlways || column.setCellValue && (isRowEditing && column.allowEditing || isCellEditing))
2266-
&& (options.rowType === 'data' || options.rowType === 'detailAdaptive') && !column.command) {
2267-
const allowUpdating = this.allowUpdating(options);
2268-
if (((allowUpdating || isRowEditing) && column.allowEditing || isCellEditing) && (isRowEditing || !isRowMode)) {
2264+
const isEditableRowType = rowType === 'data' || rowType === 'detailAdaptive';
2265+
const isEditableByRowState = isRowEditing && !!column.allowEditing;
2266+
const needsEditorTemplate = !!column.showEditorAlways
2267+
|| (column.setCellValue && (isEditableByRowState || isCellEditing));
2268+
2269+
if (needsEditorTemplate && isEditableRowType && !column.command) {
2270+
const allowUpdating = !!this.allowUpdating(options);
2271+
const canModifyCell = (allowUpdating || isRowEditing || !!row?.isNewRow)
2272+
&& !!column.allowEditing;
2273+
const isEditable = (canModifyCell || isCellEditing) && (isRowEditing || !isRowMode);
2274+
2275+
if (isEditable) {
2276+
// eslint-disable-next-line @typescript-eslint/init-declarations
2277+
let editingStartOptions;
22692278
if (column.showEditorAlways && !isRowMode) {
22702279
editingStartOptions = {
22712280
cancel: false,
2272-
key: options.row.isNewRow ? undefined : options.row.key,
2273-
data: options.row.data,
2281+
key: row?.isNewRow ? undefined : row.key,
2282+
data: row.data,
22742283
column,
22752284
};
22762285
this._isEditingStart(editingStartOptions);
@@ -2282,7 +2291,7 @@ class EditingControllerImpl extends modules.ViewController {
22822291
}
22832292
}
22842293
template = column.editCellTemplate || this._getDefaultEditorTemplate();
2285-
} else if (column.command === 'detail' && options.rowType === 'detail' && isRowEditing) {
2294+
} else if (column.command === 'detail' && rowType === 'detail' && isRowEditing) {
22862295
template = (this as any)?.getEditFormTemplate(options);
22872296
}
22882297

0 commit comments

Comments
 (0)