@@ -51,6 +51,7 @@ import {
51
51
inject ,
52
52
} from '@angular/core' ;
53
53
import { CanColor , DateAdapter , mixinColor , ThemePalette } from '@angular/material/core' ;
54
+ import { AnimationEvent } from '@angular/animations' ;
54
55
import { merge , Subject , Observable , Subscription } from 'rxjs' ;
55
56
import { filter , take } from 'rxjs/operators' ;
56
57
import { _getFocusedElementPierceShadowDom } from '@angular/cdk/platform' ;
@@ -119,7 +120,8 @@ const _MatDatepickerContentBase = mixinColor(
119
120
host : {
120
121
'class' : 'mat-datepicker-content' ,
121
122
'[@transformPanel]' : '_animationState' ,
122
- '(@transformPanel.done)' : '_animationDone.next()' ,
123
+ '(@transformPanel.start)' : '_handleAnimationEvent($event)' ,
124
+ '(@transformPanel.done)' : '_handleAnimationEvent($event)' ,
123
125
'[class.mat-datepicker-content-touch]' : 'datepicker.touchUi' ,
124
126
} ,
125
127
animations : [ matDatepickerAnimations . transformPanel , matDatepickerAnimations . fadeInCalendar ] ,
@@ -161,6 +163,9 @@ export class MatDatepickerContent<S, D = ExtractDateTypeFromSelection<S>>
161
163
/** Emits when an animation has finished. */
162
164
readonly _animationDone = new Subject < void > ( ) ;
163
165
166
+ /** Whether there is an in-progress animation. */
167
+ _isAnimating = false ;
168
+
164
169
/** Text for the close button. */
165
170
_closeButtonText : string ;
166
171
@@ -240,6 +245,14 @@ export class MatDatepickerContent<S, D = ExtractDateTypeFromSelection<S>>
240
245
this . _changeDetectorRef . markForCheck ( ) ;
241
246
}
242
247
248
+ _handleAnimationEvent ( event : AnimationEvent ) {
249
+ this . _isAnimating = event . phaseName === 'start' ;
250
+
251
+ if ( ! this . _isAnimating ) {
252
+ this . _animationDone . next ( ) ;
253
+ }
254
+ }
255
+
243
256
_getSelected ( ) {
244
257
return this . _model . selection as unknown as D | DateRange < D > | null ;
245
258
}
@@ -596,7 +609,9 @@ export abstract class MatDatepickerBase<
596
609
597
610
/** Open the calendar. */
598
611
open ( ) : void {
599
- if ( this . _opened || this . disabled ) {
612
+ // Skip reopening if there's an in-progress animation to avoid overlapping
613
+ // sequences which can cause "changed after checked" errors. See #25837.
614
+ if ( this . _opened || this . disabled || this . _componentRef ?. instance . _isAnimating ) {
600
615
return ;
601
616
}
602
617
@@ -612,7 +627,9 @@ export abstract class MatDatepickerBase<
612
627
613
628
/** Close the calendar. */
614
629
close ( ) : void {
615
- if ( ! this . _opened ) {
630
+ // Skip reopening if there's an in-progress animation to avoid overlapping
631
+ // sequences which can cause "changed after checked" errors. See #25837.
632
+ if ( ! this . _opened || this . _componentRef ?. instance . _isAnimating ) {
616
633
return ;
617
634
}
618
635
0 commit comments