{"record":{"id":"e4704f27b8a85856","repo":"angular/components","slug":"conditional-row-definitions-via-the-when-input-a","errorCode":null,"errorMessage":"Conditional row definitions via the `when` input are not supported when virtual scrolling is enabled, at the moment.","messagePattern":"Conditional row definitions via the `when` input are not supported when virtual scrolling is enabled, at the moment\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cdk/table/table.ts","lineNumber":1151,"sourceCode":"    this._headerRowDefs = mergeArrayAndSet(\n      this._getOwnDefs(this._contentHeaderRowDefs),\n      this._customHeaderRowDefs,\n    );\n    this._footerRowDefs = mergeArrayAndSet(\n      this._getOwnDefs(this._contentFooterRowDefs),\n      this._customFooterRowDefs,\n    );\n    this._rowDefs = mergeArrayAndSet(this._getOwnDefs(this._contentRowDefs), this._customRowDefs);\n\n    // After all row definitions are determined, find the row definition to be considered default.\n    const defaultRowDefs = this._rowDefs.filter(def => !def.when);\n\n    if (typeof ngDevMode === 'undefined' || ngDevMode) {\n      // At the moment of writing, it's tricky to support `when` with virtual scrolling\n      // because we reuse templates and they can change arbitrarily based on the `when`\n      // condition. We may be able to support it in the future (see #32670).\n      if (this._virtualScrollEnabled() && this._rowDefs.some(def => def.when)) {\n        throw new Error(\n          'Conditional row definitions via the `when` input are not ' +\n            'supported when virtual scrolling is enabled, at the moment.',\n        );\n      }\n\n      if (!this.multiTemplateDataRows && defaultRowDefs.length > 1) {\n        throw getTableMultipleDefaultRowDefsError();\n      }\n    }\n    this._defaultRowDef = defaultRowDefs[0];\n  }\n\n  /**\n   * Check if the header, data, or footer rows have changed what columns they want to display or\n   * whether the sticky states have changed for the header or footer. If there is a diff, then\n   * re-render that section.\n   */\n  private _renderUpdatedColumns(): boolean {","sourceCodeStart":1133,"sourceCodeEnd":1169,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/table/table.ts#L1133-L1169","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["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).","Disable virtual scrolling for the table if conditional row definitions are essential, and rely on standard CdkTable rendering.","Restructure data so all rows share one rowDef, differentiating via the renderRows data and template bindings.","Track upstream issue #32670 for future support of `when` with virtual scrolling."],"exampleFix":"<!-- before -->\n<ng-container *cdkRowDef=\"let row; columns: displayedColumns; when: isSpecialRow\">...</ng-container>\n<!-- after -->\n<ng-container *cdkRowDef=\"let row; columns: displayedColumns\">\n  <div [class.special]=\"isSpecialRow(row)\">...</div>\n</ng-container>","handlingStrategy":"validation","validationCode":"// Before enabling virtual scroll on a CdkTable, assert no rowDef uses `when`:\nconst whenRowDefs = document.querySelectorAll('ng-container[when], [cdkRowDef][when]');\nif (whenRowDefs.length > 0 && usingVirtualScroll) {\n  throw new Error('Remove `when` row defs before enabling cdk virtual scrolling');\n}","typeGuard":"function supportsVirtualScroll(rowDefs: Array<{ when?: unknown }>): boolean {\n  return rowDefs.every(d => d.when === undefined);\n}","tryCatchPattern":"try {\n  this.viewportComponent.renderRows();\n} catch (e) {\n  if (String(e.message).includes('`when` input are not supported when virtual scrolling')) {\n    console.error('Refactor row defs: replace `when` predicates with in-template conditionals.');\n  } else throw e;\n}","preventionTips":["Standardize on one rowDef and differentiate rows inside the template when virtual scrolling is on.","Add a lint/test rule that fails if [cdkRowDef] elements carry a `when` binding in virtual-scroll tables.","Track issue #32670 before adopting `when` with virtual scroll.","Keep dev builds (ngDevMode) in CI so this check fires before production."],"tags":["angular","cdk-table","virtual-scroll","dev-mode-check"],"backgroundTag":"unsupported-feature-combination","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}