Skip to content

GridCore data: Relocate filter-controller fields (headerFilter, applyFilter) - #34797

Merged
bit-byte0 merged 3 commits into
DevExpress:mainfrom
bit-byte0:refactor/gridcore-relocate-filter-controllers-26_2
Aug 18, 2026
Merged

GridCore data: Relocate filter-controller fields (headerFilter, applyFilter)#34797
bit-byte0 merged 3 commits into
DevExpress:mainfrom
bit-byte0:refactor/gridcore-relocate-filter-controllers-26_2

Conversation

@bit-byte0

Copy link
Copy Markdown
Contributor

What

Removed the _headerFilterController and _applyFilterController references from the base DataController, so it no longer depends on the header-filter and filter-row controllers

How

The temporary excluded-column context those controllers passed through their own state now lives on DataController (setFilterExcludedColumn / getFilterExcludedColumn), and the filter data-extenders read it from there instead of reaching into those controllers

@bit-byte0
bit-byte0 requested a review from a team as a code owner August 17, 2026 12:21
Copilot AI lite review requested due to automatic review settings August 17, 2026 12:21
@bit-byte0 bit-byte0 added the 26_2 label Aug 17, 2026
@bit-byte0 bit-byte0 self-assigned this Aug 17, 2026
@bit-byte0 bit-byte0 changed the title Grids: remove headerFilter/applyFilter fields from base dataController GridCore data: Relocate filter-controller fields (headerFilter, applyFilter) Aug 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR decouples the base grid DataController from the header-filter and filter-row controllers by moving the “temporarily exclude current column from combined filter” context onto DataController itself.

Changes:

  • Removed DataController references to _headerFilterController and _applyFilterController, replacing them with a new _filterExcludedColumn state.
  • Updated header filter and filter row flows to set/reset the excluded column on DataController when computing lookup-related combined filters.
  • Updated filter-sync and filter calculation logic (and QUnit coverage) to use the new excluded-column mechanism.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/filterSync.tests.js Updates tests to use dataController.setFilterExcludedColumn(...) instead of reaching into headerFilterController state.
packages/devextreme/js/__internal/grids/grid_core/header_filter/m_header_filter.ts Removes per-controller current-column state and switches to DataController excluded-column state during combined filter calculation for header filter lookups.
packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_sync.ts Replaces controller-based “current column” logic with the new excluded-column state when removing current column conditions during filter sync.
packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts Removes ApplyFilterViewController current-column state and uses DataController excluded-column state when computing combined filters / skipping current column in filter row filters.
packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts Removes controller dependencies and introduces setFilterExcludedColumn / getFilterExcludedColumn plus backing state.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_sync.ts Outdated
Copilot AI review requested due to automatic review settings August 17, 2026 16:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (8)

packages/devextreme/js/__internal/grids/grid_core/header_filter/m_header_filter.ts:267

  • Same excluded-column state issue here: if getCombinedFilter() throws, _filterExcludedColumn stays set. Use try/finally and restore the previous excluded column (not always null).
      this._dataController.setFilterExcludedColumn(column);
      const filter = this._dataController.getCombinedFilter();
      this._dataController.setFilterExcludedColumn(null);

packages/devextreme/js/__internal/grids/grid_core/header_filter/m_header_filter.ts:513

  • This code reads the protected field _filterExcludedColumn directly even though DataController now provides getFilterExcludedColumn(). Using the getter improves encapsulation and makes it possible for mocks/overrides to work correctly.
    const currentColumn = this._filterExcludedColumn;

packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts:786

  • Same excluded-column state leak risk here. Consider restoring the previous value (not hard-coding null) so nested/overlapping computations don’t clobber each other.
        this._dataController.setFilterExcludedColumn(column);
        const filter = this._dataController.getCombinedFilter() || null;
        this._dataController.setFilterExcludedColumn(null);

packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts:834

  • This extender reads _filterExcludedColumn directly; using getFilterExcludedColumn() makes the intent clearer and keeps the state access centralized on DataController.
    const excludedColumn = this._filterExcludedColumn;

packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_sync.ts:316

  • This code reads the protected field _filterExcludedColumn directly, but DataController now has getFilterExcludedColumn(). Using the getter reduces coupling to the field name and keeps mocks/overrides viable.
      const currentColumn = this._filterExcludedColumn;

packages/devextreme/js/__internal/grids/grid_core/header_filter/m_header_filter.ts:256

  • setFilterExcludedColumn(null) is executed only on the happy path. If getCombinedFilter() throws, the excluded-column state remains set and can affect subsequent filtering operations. Restore the previous excluded column in a try/finally (also preserves nesting).

This issue also appears on line 265 of the same file.

        this._dataController.setFilterExcludedColumn(column);
        const filter = this._dataController.getCombinedFilter();
        this._dataController.setFilterExcludedColumn(null);

packages/devextreme/testing/helpers/gridBaseMocks.js:241

  • gridBaseMocks exposes setFilterExcludedColumn / getFilterExcludedColumn as no-ops, which doesn’t reflect the real DataController behavior. This can cause tests that rely on the excluded-column context to silently behave differently. Consider storing the value on the mock instance so it can be read back.
            setFilterExcludedColumn: commonUtils.noop,

            getFilterExcludedColumn: commonUtils.noop,

packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts:555

  • setFilterExcludedColumn(null) runs only if getCombinedFilter() succeeds. If it throws, the excluded-column state is left set and can leak into later filter computations. Wrap with try/finally and restore the previous excluded column value.

This issue also appears on line 784 of the same file.

      this._dataController.setFilterExcludedColumn(options);
      const filter = this._dataController.getCombinedFilter();
      this._dataController.setFilterExcludedColumn(null);

protected _headerFilterController!: HeaderFilterController;

protected _applyFilterController!: ApplyFilterViewController;
protected _filterExcludedColumn: Column | null = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small suggestion: make _filterExcludedColumn private and use getFilterExcludedColumn() where needed. Currently getFilterExcludedColumn is not used anywhere

const currentColumnForFilterRow = this._applyFilterController.getCurrentColumnForFiltering();
const currentColumn = currentColumnForHeaderFilter || currentColumnForFilterRow;
const needRemoveCurrentColumnFilter = currentColumnForHeaderFilter || isDefined(currentColumnForFilterRow?.filterValue);
const currentColumn = this._filterExcludedColumn;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: rename to excludedColumn

const columns = that._columnsController.getVisibleColumns(null, true);
const headerFilterController = this._headerFilterController;
const currentColumn = headerFilterController.getCurrentColumn();
const currentColumn = this._filterExcludedColumn;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: rename to excludedColumn

this._dataController.setFilterExcludedColumn(options);
const filter = this._dataController.getCombinedFilter();
this._applyFilterViewController.setCurrentColumnForFiltering(null);
this._dataController.setFilterExcludedColumn(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We repeat this construct 4 times, perhaps, we should create another method instead, smth like getCombinedFilterWithExculdedColumn

Copilot AI review requested due to automatic review settings August 18, 2026 10:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (2)

packages/devextreme/js/__internal/grids/grid_core/data_controller/data_controller.ts:364

  • PR description mentions setFilterExcludedColumn / getFilterExcludedColumn, but DataController only exposes getFilterExcludedColumn and relies on getCombinedFilterWithExcludedColumn to mutate internal state. Consider adding setFilterExcludedColumn (or updating the description) and restoring the previous excluded column in finally (instead of always resetting to null) so nested/re-entrant calls don’t accidentally clear the state.
  public getCombinedFilterWithExcludedColumn(
    excludedColumn: Column | null,
    returnDataField?: boolean,
  ): DataFilter {
    this._filterExcludedColumn = excludedColumn;

packages/devextreme/testing/helpers/gridBaseMocks.js:241

  • gridBaseMocks stubs getFilterExcludedColumn / getCombinedFilterWithExcludedColumn as noop, but the real controller returns null (no excluded column) and getCombinedFilterWithExcludedColumn delegates to getCombinedFilter. Using noop here can make mocks diverge from production behavior if a test overrides getCombinedFilter.
            getFilterExcludedColumn: commonUtils.noop,

            getCombinedFilterWithExcludedColumn: commonUtils.noop,

@bit-byte0
bit-byte0 added this pull request to the merge queue Aug 18, 2026
Merged via the queue into DevExpress:main with commit 98fcd9c Aug 18, 2026
101 checks passed
@bit-byte0
bit-byte0 deleted the refactor/gridcore-relocate-filter-controllers-26_2 branch August 18, 2026 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants