@@ -24,6 +24,7 @@ import {ViewportRuler} from '@angular/cdk/scrolling';
24
24
import { DOCUMENT } from '@angular/common' ;
25
25
import {
26
26
AfterContentChecked ,
27
+ AfterContentInit ,
27
28
Attribute ,
28
29
ChangeDetectionStrategy ,
29
30
ChangeDetectorRef ,
@@ -285,7 +286,9 @@ export interface RenderRow<T> {
285
286
standalone : true ,
286
287
imports : [ HeaderRowOutlet , DataRowOutlet , NoDataRowOutlet , FooterRowOutlet ] ,
287
288
} )
288
- export class CdkTable < T > implements AfterContentChecked , CollectionViewer , OnDestroy , OnInit {
289
+ export class CdkTable < T >
290
+ implements AfterContentInit , AfterContentChecked , CollectionViewer , OnDestroy , OnInit
291
+ {
289
292
private _document : Document ;
290
293
291
294
/** Latest data provided by the data source. */
@@ -433,7 +436,10 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
433
436
private _isShowingNoDataRow = false ;
434
437
435
438
/** Whether the table has rendered out all the outlets for the first time. */
436
- private _hasRendered = false ;
439
+ private _hasAllOutlets = false ;
440
+
441
+ /** Whether the table is done initializing. */
442
+ private _hasInitialized = false ;
437
443
438
444
/** Aria role to apply to the table's cells based on the table's own role. */
439
445
_getCellRole ( ) : string | null {
@@ -641,9 +647,13 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
641
647
} ) ;
642
648
}
643
649
650
+ ngAfterContentInit ( ) {
651
+ this . _hasInitialized = true ;
652
+ }
653
+
644
654
ngAfterContentChecked ( ) {
645
655
// Only start re-rendering in `ngAfterContentChecked` after the first render.
646
- if ( this . _hasRendered ) {
656
+ if ( this . _canRender ( ) ) {
647
657
this . _render ( ) ;
648
658
}
649
659
}
@@ -902,17 +912,27 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
902
912
// Also we can't use queries to resolve the outlets, because they're wrapped in a
903
913
// conditional, so we have to rely on them being assigned via DI.
904
914
if (
905
- ! this . _hasRendered &&
915
+ ! this . _hasAllOutlets &&
906
916
this . _rowOutlet &&
907
917
this . _headerRowOutlet &&
908
918
this . _footerRowOutlet &&
909
919
this . _noDataRowOutlet
910
920
) {
911
- this . _hasRendered = true ;
912
- this . _render ( ) ;
921
+ this . _hasAllOutlets = true ;
922
+
923
+ // In some setups this may fire before `ngAfterContentInit`
924
+ // so we need a check here. See #28538.
925
+ if ( this . _canRender ( ) ) {
926
+ this . _render ( ) ;
927
+ }
913
928
}
914
929
}
915
930
931
+ /** Whether the table has all the information to start rendering. */
932
+ private _canRender ( ) : boolean {
933
+ return this . _hasAllOutlets && this . _hasInitialized ;
934
+ }
935
+
916
936
/** Renders the table if its state has changed. */
917
937
private _render ( ) : void {
918
938
// Cache the row and column definitions gathered by ContentChildren and programmatic injection.
0 commit comments