angular/components · error · Error

Conditional row definitions via the `when` input are not sup

Error message

Conditional row definitions via the `when` input are not supported when virtual scrolling is enabled, at the moment.

What it means

CdkTable (src/cdk/table/table.ts) validates its inputs during change detection. Row definitions using the `when` predicate input cannot be combined with virtual scrolling, because templates are reused/recycled by the virtual scroll viewport and can change arbitrarily based on the `when` condition (see upstream issue #32670). When both are active in ngDevMode builds, the component throws this Error deliberately to prevent incorrect rendering.

Source

Thrown at src/cdk/table/table.ts:1151

    this._headerRowDefs = mergeArrayAndSet(
      this._getOwnDefs(this._contentHeaderRowDefs),
      this._customHeaderRowDefs,
    );
    this._footerRowDefs = mergeArrayAndSet(
      this._getOwnDefs(this._contentFooterRowDefs),
      this._customFooterRowDefs,
    );
    this._rowDefs = mergeArrayAndSet(this._getOwnDefs(this._contentRowDefs), this._customRowDefs);

    // After all row definitions are determined, find the row definition to be considered default.
    const defaultRowDefs = this._rowDefs.filter(def => !def.when);

    if (typeof ngDevMode === 'undefined' || ngDevMode) {
      // At the moment of writing, it's tricky to support `when` with virtual scrolling
      // because we reuse templates and they can change arbitrarily based on the `when`
      // condition. We may be able to support it in the future (see #32670).
      if (this._virtualScrollEnabled() && this._rowDefs.some(def => def.when)) {
        throw new Error(
          'Conditional row definitions via the `when` input are not ' +
            'supported when virtual scrolling is enabled, at the moment.',
        );
      }

      if (!this.multiTemplateDataRows && defaultRowDefs.length > 1) {
        throw getTableMultipleDefaultRowDefsError();
      }
    }
    this._defaultRowDef = defaultRowDefs[0];
  }

  /**
   * Check if the header, data, or footer rows have changed what columns they want to display or
   * whether the sticky states have changed for the header or footer. If there is a diff, then
   * re-render that section.
   */
  private _renderUpdatedColumns(): boolean {

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Remove the `when` input from all row definitions and instead switch on row data inside a single row template (e.g. ngIf/ngSwitch within the row template or use data-driven classes).
  2. Disable virtual scrolling for the table if conditional row definitions are essential, and rely on standard CdkTable rendering.
  3. Restructure data so all rows share one rowDef, differentiating via the renderRows data and template bindings.
  4. Track upstream issue #32670 for future support of `when` with virtual scrolling.

Example fix

<!-- before -->
<ng-container *cdkRowDef="let row; columns: displayedColumns; when: isSpecialRow">...</ng-container>
<!-- after -->
<ng-container *cdkRowDef="let row; columns: displayedColumns">
  <div [class.special]="isSpecialRow(row)">...</div>
</ng-container>
Defensive patterns

Strategy: validation

Validate before calling

// Before enabling virtual scroll on a CdkTable, assert no rowDef uses `when`:
const whenRowDefs = document.querySelectorAll('ng-container[when], [cdkRowDef][when]');
if (whenRowDefs.length > 0 && usingVirtualScroll) {
  throw new Error('Remove `when` row defs before enabling cdk virtual scrolling');
}

Type guard

function supportsVirtualScroll(rowDefs: Array<{ when?: unknown }>): boolean {
  return rowDefs.every(d => d.when === undefined);
}

Try / catch

try {
  this.viewportComponent.renderRows();
} catch (e) {
  if (String(e.message).includes('`when` input are not supported when virtual scrolling')) {
    console.error('Refactor row defs: replace `when` predicates with in-template conditionals.');
  } else throw e;
}

Prevention

When it happens

Trigger: Rendering a <table cdk-table> (or cdk-virtual-scroll based table) where cdkRowDef / *cdkRowDef="let row; when: myWhenFn" rows exist while the virtual scroll is enabled (using <cdk-virtual-scroll-viewport> with the table / multiTemplateDataRows disabled paths that enable _virtualScrollEnabled).

Common situations: Adding `when`-based conditional row styling/structure to an already virtual-scrolling table for large datasets; migrating a regular CdkTable into a virtual scroll viewport and keeping existing `when` row defs; following older tutorials predating this restriction.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/e4704f27b8a85856. Report an issue: GitHub.