Skip to content

Commit

Permalink
fix(cdk/table): error if outlets are assigned too early (#28551)
Browse files Browse the repository at this point in the history
Fixes that the table was throwing an error if all outlets are assigned before `ngAfterContentInit`.

Fixes #28538.
  • Loading branch information
crisbeto authored Feb 8, 2024
1 parent f1e82da commit add3cd4
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 11 deletions.
10 changes: 6 additions & 4 deletions src/cdk/table/sticky-styler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,12 @@ export class StickyStyler {
this._coalescedStyleScheduler.schedule(() => {
const tfoot = tableElement.querySelector('tfoot')!;

if (stickyStates.some(state => !state)) {
this._removeStickyStyle(tfoot, ['bottom']);
} else {
this._addStickyStyle(tfoot, 'bottom', 0, false);
if (tfoot) {
if (stickyStates.some(state => !state)) {
this._removeStickyStyle(tfoot, ['bottom']);
} else {
this._addStickyStyle(tfoot, 'bottom', 0, false);
}
}
});
}
Expand Down
32 changes: 26 additions & 6 deletions src/cdk/table/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {ViewportRuler} from '@angular/cdk/scrolling';
import {DOCUMENT} from '@angular/common';
import {
AfterContentChecked,
AfterContentInit,
Attribute,
ChangeDetectionStrategy,
ChangeDetectorRef,
Expand Down Expand Up @@ -285,7 +286,9 @@ export interface RenderRow<T> {
standalone: true,
imports: [HeaderRowOutlet, DataRowOutlet, NoDataRowOutlet, FooterRowOutlet],
})
export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDestroy, OnInit {
export class CdkTable<T>
implements AfterContentInit, AfterContentChecked, CollectionViewer, OnDestroy, OnInit
{
private _document: Document;

/** Latest data provided by the data source. */
Expand Down Expand Up @@ -433,7 +436,10 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
private _isShowingNoDataRow = false;

/** Whether the table has rendered out all the outlets for the first time. */
private _hasRendered = false;
private _hasAllOutlets = false;

/** Whether the table is done initializing. */
private _hasInitialized = false;

/** Aria role to apply to the table's cells based on the table's own role. */
_getCellRole(): string | null {
Expand Down Expand Up @@ -641,9 +647,13 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
});
}

ngAfterContentInit() {
this._hasInitialized = true;
}

ngAfterContentChecked() {
// Only start re-rendering in `ngAfterContentChecked` after the first render.
if (this._hasRendered) {
if (this._canRender()) {
this._render();
}
}
Expand Down Expand Up @@ -902,17 +912,27 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
// Also we can't use queries to resolve the outlets, because they're wrapped in a
// conditional, so we have to rely on them being assigned via DI.
if (
!this._hasRendered &&
!this._hasAllOutlets &&
this._rowOutlet &&
this._headerRowOutlet &&
this._footerRowOutlet &&
this._noDataRowOutlet
) {
this._hasRendered = true;
this._render();
this._hasAllOutlets = true;

// In some setups this may fire before `ngAfterContentInit`
// so we need a check here. See #28538.
if (this._canRender()) {
this._render();
}
}
}

/** Whether the table has all the information to start rendering. */
private _canRender(): boolean {
return this._hasAllOutlets && this._hasInitialized;
}

/** Renders the table if its state has changed. */
private _render(): void {
// Cache the row and column definitions gathered by ContentChildren and programmatic injection.
Expand Down
5 changes: 4 additions & 1 deletion tools/public_api_guard/cdk/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
```ts

import { AfterContentChecked } from '@angular/core';
import { AfterContentInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { ChangeDetectorRef } from '@angular/core';
import { CollectionViewer } from '@angular/cdk/collections';
Expand Down Expand Up @@ -288,7 +289,7 @@ export class CdkRowDef<T> extends BaseRowDef {
}

// @public
export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDestroy, OnInit {
export class CdkTable<T> implements AfterContentInit, AfterContentChecked, CollectionViewer, OnDestroy, OnInit {
constructor(_differs: IterableDiffers, _changeDetectorRef: ChangeDetectorRef, _elementRef: ElementRef, role: string, _dir: Directionality, _document: any, _platform: Platform, _viewRepeater: _ViewRepeater<T, RenderRow<T>, RowContext<T>>, _coalescedStyleScheduler: _CoalescedStyleScheduler, _viewportRuler: ViewportRuler,
_stickyPositioningListener: StickyPositioningListener,
_ngZone?: NgZone | undefined);
Expand Down Expand Up @@ -337,6 +338,8 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
// (undocumented)
ngAfterContentChecked(): void;
// (undocumented)
ngAfterContentInit(): void;
// (undocumented)
ngOnDestroy(): void;
// (undocumented)
ngOnInit(): void;
Expand Down

0 comments on commit add3cd4

Please sign in to comment.