From 9d079905a703949d87ba95c0876101095e9c5c7d Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:50:18 +0400 Subject: [PATCH 1/2] fix(dataGrid): sync filter row editor with filter panel when applyFilter is onClick --- .../m_filter_row.integration.test.ts | 27 +++++++++++++++++++ .../grids/grid_core/filter/m_filter_sync.ts | 13 +++++---- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/filter/__tests__/m_filter_row.integration.test.ts b/packages/devextreme/js/__internal/grids/grid_core/filter/__tests__/m_filter_row.integration.test.ts index 769712af18f1..64f9d690cbb8 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/filter/__tests__/m_filter_row.integration.test.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/filter/__tests__/m_filter_row.integration.test.ts @@ -5,6 +5,7 @@ import { } from '@jest/globals'; import type { EditorPreparingEvent } from '@js/ui/data_grid'; import { TagBoxModel } from '@ts/ui/__tests__/__mock__/model/tag_box'; +import { TextBoxModel } from '@ts/ui/__tests__/__mock__/model/textbox'; import { afterTest, @@ -68,4 +69,30 @@ describe('FilterRow', () => { expect(tagBox.getTags()).toHaveLength(2); }); }); + + describe('sync with filter panel when applyFilter is onClick (T1331971)', () => { + it('should update the filter row editor when the condition is changed via the filter panel', async () => { + const { component, instance } = await createDataGrid({ + dataSource: [ + { id: 1, city: 'Las Vegas' }, + { id: 2, city: 'San Jose' }, + ], + filterRow: { visible: true, applyFilter: 'onClick' }, + filterPanel: { visible: true }, + columns: ['city'], + }); + + await flushAsync(); + + instance.option('filterValue', ['city', 'contains', 'Las']); + await flushAsync(); + + instance.option('filterValue', ['city', 'contains', 'San']); + await flushAsync(); + + const editor = component.getFilterRow().getFilterCell(0).getEditor(TextBoxModel); + + expect(editor.getInput().value).toBe('San'); + }); + }); }); diff --git a/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_sync.ts b/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_sync.ts index bf7335f681b7..0ee46cea67b6 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_sync.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_sync.ts @@ -101,11 +101,11 @@ const getConditionFromHeaderFilter = function (column) { canSyncHeaderFilterWithFilterRow(column) && !Array.isArray(filterValues[0]) )) { - column.filterType === FILTER_TYPES_EXCLUDE ? selectedOperation = '<>' : selectedOperation = '='; + selectedOperation = column.filterType === FILTER_TYPES_EXCLUDE ? '<>' : '='; // eslint-disable-next-line prefer-destructuring value = filterValues[0]; } else { - column.filterType === FILTER_TYPES_EXCLUDE ? selectedOperation = 'noneof' : selectedOperation = 'anyof'; + selectedOperation = column.filterType === FILTER_TYPES_EXCLUDE ? 'noneof' : 'anyof'; value = filterValues; } return [getColumnIdentifier(column), selectedOperation, value]; @@ -122,7 +122,7 @@ const updateFilterRowCondition = function (columnsController, column, condition) const filterValue = condition?.[2]; const filterOperations = column.filterOperations || column.defaultFilterOperations; - const selectedOperationExists = !filterOperations || filterOperations.indexOf(selectedFilterOperation) >= 0; + const selectedOperationExists = !filterOperations || filterOperations.includes(selectedFilterOperation); const defaultOperationSelected = selectedFilterOperation === column.defaultFilterOperation; const builtInOperationSelected = FILTER_ROW_OPERATIONS.includes(selectedFilterOperation); const filterValueNotNullOrEmpty = filterValue !== null && filterValue !== ''; @@ -134,11 +134,15 @@ const updateFilterRowCondition = function (columnsController, column, condition) filterRowOptions = { filterValue, selectedFilterOperation, + bufferedFilterValue: undefined, + bufferedSelectedFilterOperation: undefined, }; } else { filterRowOptions = { filterValue: undefined, selectedFilterOperation: undefined, + bufferedFilterValue: undefined, + bufferedSelectedFilterOperation: undefined, }; } columnsController.columnOption(getColumnIdentifier(column), filterRowOptions); @@ -170,12 +174,11 @@ export class FilterSyncController extends modules.Controller { } public syncFilterValue() { - const that = this; const columns = this._columnsController.getFilteringColumns(); this._skipSyncColumnOptions = true; columns.forEach((column) => { - const filterConditions = getMatchedConditions(that.option('filterValue'), getColumnIdentifier(column)); + const filterConditions = getMatchedConditions(this.option('filterValue'), getColumnIdentifier(column)); if (filterConditions.length === 1) { const filterCondition = filterConditions[0]; updateHeaderFilterCondition(this._columnsController, column, filterCondition); From dc9db9c23b1d1dc44be1a0bdb2d5aff4fc9c3c02 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:39:30 +0400 Subject: [PATCH 2/2] test(dataGrid): cover filter row reset sync when applyFilter is onClick --- .../m_filter_row.integration.test.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/devextreme/js/__internal/grids/grid_core/filter/__tests__/m_filter_row.integration.test.ts b/packages/devextreme/js/__internal/grids/grid_core/filter/__tests__/m_filter_row.integration.test.ts index 64f9d690cbb8..42a8725fa1d5 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/filter/__tests__/m_filter_row.integration.test.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/filter/__tests__/m_filter_row.integration.test.ts @@ -94,5 +94,29 @@ describe('FilterRow', () => { expect(editor.getInput().value).toBe('San'); }); + + it('should clear the filter row editor when the filter is reset via the filter panel', async () => { + const { component, instance } = await createDataGrid({ + dataSource: [ + { id: 1, city: 'Las Vegas' }, + { id: 2, city: 'San Jose' }, + ], + filterRow: { visible: true, applyFilter: 'onClick' }, + filterPanel: { visible: true }, + columns: ['city'], + }); + + await flushAsync(); + + instance.option('filterValue', ['city', 'contains', 'Las']); + await flushAsync(); + + instance.option('filterValue', null as any); + await flushAsync(); + + const editor = component.getFilterRow().getFilterCell(0).getEditor(TextBoxModel); + + expect(editor.getInput().value).toBe(''); + }); }); });