@@ -24,6 +24,7 @@ import {ViewportRuler} from '@angular/cdk/scrolling';
2424import { DOCUMENT } from '@angular/common' ;
2525import {
2626 AfterContentChecked ,
27+ AfterContentInit ,
2728 Attribute ,
2829 ChangeDetectionStrategy ,
2930 ChangeDetectorRef ,
@@ -285,7 +286,9 @@ export interface RenderRow<T> {
285286 standalone : true ,
286287 imports : [ HeaderRowOutlet , DataRowOutlet , NoDataRowOutlet , FooterRowOutlet ] ,
287288} )
288- export class CdkTable < T > implements AfterContentChecked , CollectionViewer , OnDestroy , OnInit {
289+ export class CdkTable < T >
290+ implements AfterContentInit , AfterContentChecked , CollectionViewer , OnDestroy , OnInit
291+ {
289292 private _document : Document ;
290293
291294 /** Latest data provided by the data source. */
@@ -433,7 +436,10 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
433436 private _isShowingNoDataRow = false ;
434437
435438 /** 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 ;
437443
438444 /** Aria role to apply to the table's cells based on the table's own role. */
439445 _getCellRole ( ) : string | null {
@@ -641,9 +647,13 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
641647 } ) ;
642648 }
643649
650+ ngAfterContentInit ( ) {
651+ this . _hasInitialized = true ;
652+ }
653+
644654 ngAfterContentChecked ( ) {
645655 // Only start re-rendering in `ngAfterContentChecked` after the first render.
646- if ( this . _hasRendered ) {
656+ if ( this . _canRender ( ) ) {
647657 this . _render ( ) ;
648658 }
649659 }
@@ -902,17 +912,27 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
902912 // Also we can't use queries to resolve the outlets, because they're wrapped in a
903913 // conditional, so we have to rely on them being assigned via DI.
904914 if (
905- ! this . _hasRendered &&
915+ ! this . _hasAllOutlets &&
906916 this . _rowOutlet &&
907917 this . _headerRowOutlet &&
908918 this . _footerRowOutlet &&
909919 this . _noDataRowOutlet
910920 ) {
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+ }
913928 }
914929 }
915930
931+ /** Whether the table has all the information to start rendering. */
932+ private _canRender ( ) : boolean {
933+ return this . _hasAllOutlets && this . _hasInitialized ;
934+ }
935+
916936 /** Renders the table if its state has changed. */
917937 private _render ( ) : void {
918938 // Cache the row and column definitions gathered by ContentChildren and programmatic injection.
0 commit comments