@@ -9,18 +9,18 @@ import {FocusTrap} from '@angular/cdk/a11y';
99import { OverlayRef , OverlaySizeConfig , PositionStrategy } from '@angular/cdk/overlay' ;
1010import { TemplatePortal } from '@angular/cdk/portal' ;
1111import {
12- afterRender ,
12+ afterNextRender ,
1313 AfterViewInit ,
1414 Directive ,
1515 ElementRef ,
1616 EmbeddedViewRef ,
17+ inject ,
18+ ListenerOptions ,
1719 NgZone ,
1820 OnDestroy ,
21+ Renderer2 ,
1922 TemplateRef ,
2023 ViewContainerRef ,
21- inject ,
22- Renderer2 ,
23- ListenerOptions ,
2424} from '@angular/core' ;
2525import { merge , Observable , Subject } from 'rxjs' ;
2626import {
@@ -35,8 +35,10 @@ import {
3535 withLatestFrom ,
3636} from 'rxjs/operators' ;
3737
38+ import { _bindEventWithOptions } from '@angular/cdk/platform' ;
3839import { CELL_SELECTOR , EDIT_PANE_CLASS , EDIT_PANE_SELECTOR , ROW_SELECTOR } from './constants' ;
3940import { EditEventDispatcher , HoverContentState } from './edit-event-dispatcher' ;
41+ import { EditRef } from './edit-ref' ;
4042import { EditServices } from './edit-services' ;
4143import { FocusDispatcher } from './focus-dispatcher' ;
4244import {
@@ -45,8 +47,6 @@ import {
4547 FocusEscapeNotifierFactory ,
4648} from './focus-escape-notifier' ;
4749import { closest } from './polyfill' ;
48- import { EditRef } from './edit-ref' ;
49- import { _bindEventWithOptions } from '@angular/cdk/platform' ;
5050
5151/**
5252 * Describes the number of columns before and after the originating cell that the
@@ -80,11 +80,24 @@ export class CdkEditable implements AfterViewInit, OnDestroy {
8080
8181 protected readonly destroyed = new Subject < void > ( ) ;
8282
83- private _rendered = new Subject ( ) ;
83+ private _rowsRendered = new Subject ( ) ;
84+
85+ private _rowMutationObserver = globalThis . MutationObserver
86+ ? new globalThis . MutationObserver ( mutations => {
87+ if ( mutations . some ( m => this . _isRowMutation ( m ) ) ) {
88+ this . _rowsRendered . next ( ) ;
89+ }
90+ } )
91+ : null ;
8492
8593 constructor ( ) {
86- afterRender ( ( ) => {
87- this . _rendered . next ( ) ;
94+ // Keep track of when the rendered rows changes.
95+ afterNextRender ( ( ) => {
96+ this . _rowsRendered . next ( ) ;
97+ this . _rowMutationObserver ?. observe ( this . elementRef . nativeElement , {
98+ childList : true ,
99+ subtree : true ,
100+ } ) ;
88101 } ) ;
89102 }
90103
@@ -95,7 +108,29 @@ export class CdkEditable implements AfterViewInit, OnDestroy {
95108 ngOnDestroy ( ) : void {
96109 this . destroyed . next ( ) ;
97110 this . destroyed . complete ( ) ;
98- this . _rendered . complete ( ) ;
111+ this . _rowMutationObserver ?. disconnect ( ) ;
112+ }
113+
114+ private _isRowMutation ( mutation : MutationRecord ) : boolean {
115+ for ( let i = 0 ; i < mutation . addedNodes . length ; i ++ ) {
116+ const el = mutation . addedNodes [ i ] ;
117+ if ( ! ( el instanceof HTMLElement ) ) {
118+ continue ;
119+ }
120+ if ( el . matches ( ROW_SELECTOR ) ) {
121+ return true ;
122+ }
123+ }
124+ for ( let i = 0 ; i < mutation . removedNodes . length ; i ++ ) {
125+ const el = mutation . removedNodes [ i ] ;
126+ if ( ! ( el instanceof HTMLElement ) ) {
127+ continue ;
128+ }
129+ if ( el . matches ( ROW_SELECTOR ) ) {
130+ return true ;
131+ }
132+ }
133+ return false ;
99134 }
100135
101136 private _observableFromEvent < T extends Event > (
@@ -153,7 +188,7 @@ export class CdkEditable implements AfterViewInit, OnDestroy {
153188 // Keep track of rows within the table. This is used to know which rows with hover content
154189 // are first or last in the table. They are kept focusable in case focus enters from above
155190 // or below the table.
156- this . _rendered
191+ this . _rowsRendered
157192 . pipe (
158193 // Avoid some timing inconsistencies since Angular v19.
159194 debounceTime ( 0 ) ,
0 commit comments