Skip to content

Commit f606c4d

Browse files
tongsonbarbswdevfx
andauthored
DataGrid - Header filter search input loses focus on first key in datetime columns (T1284663) (DevExpress#29768)
Co-authored-by: wdevfx <[email protected]>
1 parent 7e78e9a commit f606c4d

File tree

3 files changed

+88
-11
lines changed

3 files changed

+88
-11
lines changed

e2e/testcafe-devextreme/tests/dataGrid/common/headerFilter/headerFilter.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,45 @@ test('[T1284200] Should handle dxList "selectAll" when has unselected items on t
316316
visible: true,
317317
},
318318
}));
319+
320+
test('Header filter search input loses focus on first key in datetime columns (T1284663)', async (t) => {
321+
const dataGrid = new DataGrid('#container');
322+
const headerCell = dataGrid.getHeaders()
323+
.getHeaderRow(0)
324+
.getHeaderCell(0);
325+
const filterIconElement = headerCell.getFilterIcon();
326+
const headerFilter = new HeaderFilter();
327+
328+
await t
329+
.click(filterIconElement)
330+
.pressKey('1');
331+
332+
await t.wait(1500);
333+
334+
const searchInput = headerFilter.getSearchInput();
335+
336+
await t
337+
.expect(searchInput.focused)
338+
.ok();
339+
}).before(async () => createWidget('dxDataGrid', {
340+
dataSource: [{
341+
id: 1,
342+
DeliveryDate: '2017/04/13 9:00',
343+
}],
344+
headerFilter: {
345+
visible: true,
346+
},
347+
keyExpr: 'id',
348+
columns: [{
349+
dataField: 'DeliveryDate',
350+
dataType: 'date',
351+
headerFilter: {
352+
dataSource: [
353+
{ text: 'March 11, 2025', value: '2025-03-11T00:00:00' },
354+
{ text: 'March 2, 2025', value: '2025-03-02T00:00:00' },
355+
{ text: 'February 3, 2025', value: '2025-02-03T00:00:00' },
356+
],
357+
search: { enabled: true },
358+
},
359+
}],
360+
}));

packages/devextreme/js/__internal/grids/grid_core/header_filter/m_header_filter_core.ts

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import '@ts/ui/list/modules/m_search';
33
import '@ts/ui/list/modules/m_selection';
44

5+
import type { ChangedOptionInfo } from '@js/common/core/events';
56
import messageLocalization from '@js/common/core/localization/message';
67
import $ from '@js/core/renderer';
78
import type { DeferredObj } from '@js/core/utils/deferred';
@@ -15,6 +16,7 @@ import Popup from '@js/ui/popup/ui.popup';
1516
import TreeView from '@js/ui/tree_view';
1617
import Modules from '@ts/grids/grid_core/m_modules';
1718
import type { ModuleType } from '@ts/grids/grid_core/m_types';
19+
import type TextBox from '@ts/ui/text_box/m_text_box';
1820

1921
import gridCoreUtils from '../m_utils';
2022

@@ -329,24 +331,52 @@ export class HeaderFilterView extends Modules.View {
329331
},
330332
};
331333

332-
function onOptionChanged(e) {
333-
// T835492, T833015
334-
if (e.fullName === 'searchValue' && needShowSelectAllCheckbox && that.option('headerFilter.hideSelectAllOnSearch') !== false) {
335-
if (options.type === 'tree') {
336-
e.component.option('showCheckBoxesMode', e.value ? 'normal' : 'selectAll');
337-
} else {
338-
e.component.option('selectionMode', e.value ? 'multiple' : 'all');
339-
}
334+
const shouldChangeSelectAllCheckBoxVisibility = (): boolean => needShowSelectAllCheckbox
335+
&& that.option('headerFilter.hideSelectAllOnSearch') !== false;
336+
337+
const onTreeViewOptionChanged = (
338+
event: ChangedOptionInfo & {
339+
component: TreeView & { _searchEditor: TextBox };
340+
},
341+
): void => {
342+
switch (true) {
343+
case event.fullName === 'searchValue' && shouldChangeSelectAllCheckBoxVisibility():
344+
event.component.option('showCheckBoxesMode', event.value ? 'normal' : 'selectAll');
345+
break;
346+
// TODO TreeView: remove this WA after Navigation squad re-render fix
347+
// NOTE: WA for TreeView re-render after changing the "showCheckBoxesMode" option
348+
// After this option change the whole TreeView re-render and search input loose the focus
349+
case event.fullName === 'showCheckBoxesMode':
350+
// NOTE: the TreeView render is async
351+
// So we should focus the searchEditor only after render will be completed
352+
Promise.resolve()
353+
.then(() => {
354+
event.component._searchEditor.focus();
355+
})
356+
.catch(() => {});
357+
break;
358+
default:
359+
break;
340360
}
341-
}
361+
};
362+
363+
const onListOptionChanged = (
364+
event: ChangedOptionInfo & {
365+
component: dxList;
366+
},
367+
): void => {
368+
if (event.fullName === 'searchValue' && shouldChangeSelectAllCheckBoxVisibility()) {
369+
event.component.option('selectionMode', event.value ? 'multiple' : 'all');
370+
}
371+
};
342372

343373
if (options.type === 'tree') {
344374
that._listComponent = that._createComponent(
345375
$('<div>').appendTo($content),
346376
TreeView,
347377
extend(widgetOptions, {
348378
showCheckBoxesMode: needShowSelectAllCheckbox ? 'selectAll' : 'normal',
349-
onOptionChanged,
379+
onOptionChanged: onTreeViewOptionChanged,
350380
keyExpr: 'id',
351381
}),
352382
);
@@ -359,7 +389,7 @@ export class HeaderFilterView extends Modules.View {
359389
pageLoadMode: 'scrollBottom',
360390
showSelectionControls: true,
361391
selectionMode: needShowSelectAllCheckbox ? 'all' : 'multiple',
362-
onOptionChanged,
392+
onOptionChanged: onListOptionChanged,
363393
onSelectionChanged(event) {
364394
const { component: listComponent } = event;
365395
const items = listComponent.option('items');

packages/testcafe-models/dataGrid/headers/headerFilter.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const CLASS = {
66
content: 'dx-overlay-content',
77
list: 'dx-list',
88
button: 'dx-button',
9+
searchInput: 'dx-texteditor-input',
910
};
1011

1112
export default class HeaderFilter {
@@ -24,4 +25,8 @@ export default class HeaderFilter {
2425
getContent(): Selector {
2526
return this.element.find(`.${CLASS.content}`);
2627
}
28+
29+
getSearchInput(): Selector {
30+
return this.element.find(`.${CLASS.searchInput}`);
31+
}
2732
}

0 commit comments

Comments
 (0)