@@ -35,6 +35,7 @@ import {
35
35
ViewChild ,
36
36
ViewContainerRef ,
37
37
ViewEncapsulation ,
38
+ ChangeDetectorRef ,
38
39
} from '@angular/core' ;
39
40
import {
40
41
CanColor ,
@@ -92,7 +93,8 @@ const _MatDatepickerContentMixinBase: CanColorCtor & typeof MatDatepickerContent
92
93
styleUrls : [ 'datepicker-content.css' ] ,
93
94
host : {
94
95
'class' : 'mat-datepicker-content' ,
95
- '[@transformPanel]' : '"enter"' ,
96
+ '[@transformPanel]' : '_animationState' ,
97
+ '(@transformPanel.done)' : '_animationDone.next()' ,
96
98
'[class.mat-datepicker-content-touch]' : 'datepicker.touchUi' ,
97
99
} ,
98
100
animations : [
@@ -105,7 +107,7 @@ const _MatDatepickerContentMixinBase: CanColorCtor & typeof MatDatepickerContent
105
107
inputs : [ 'color' ] ,
106
108
} )
107
109
export class MatDatepickerContent < D > extends _MatDatepickerContentMixinBase
108
- implements AfterViewInit , CanColor {
110
+ implements AfterViewInit , OnDestroy , CanColor {
109
111
110
112
/** Reference to the internal calendar component. */
111
113
@ViewChild ( MatCalendar ) _calendar : MatCalendar < D > ;
@@ -116,13 +118,38 @@ export class MatDatepickerContent<D> extends _MatDatepickerContentMixinBase
116
118
/** Whether the datepicker is above or below the input. */
117
119
_isAbove : boolean ;
118
120
119
- constructor ( elementRef : ElementRef ) {
121
+ /** Current state of the animation. */
122
+ _animationState : 'enter' | 'void' = 'enter' ;
123
+
124
+ /** Emits when an animation has finished. */
125
+ _animationDone = new Subject < void > ( ) ;
126
+
127
+ constructor (
128
+ elementRef : ElementRef ,
129
+ /**
130
+ * @deprecated `_changeDetectorRef` parameter to become required.
131
+ * @breaking -change 11.0.0
132
+ */
133
+ private _changeDetectorRef ?: ChangeDetectorRef ) {
120
134
super ( elementRef ) ;
121
135
}
122
136
123
137
ngAfterViewInit ( ) {
124
138
this . _calendar . focusActiveCell ( ) ;
125
139
}
140
+
141
+ ngOnDestroy ( ) {
142
+ this . _animationDone . complete ( ) ;
143
+ }
144
+
145
+ _startExitAnimation ( ) {
146
+ this . _animationState = 'void' ;
147
+
148
+ // @breaking -change 11.0.0 Remove null check for `_changeDetectorRef`.
149
+ if ( this . _changeDetectorRef ) {
150
+ this . _changeDetectorRef . markForCheck ( ) ;
151
+ }
152
+ }
126
153
}
127
154
128
155
@@ -250,14 +277,11 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
250
277
}
251
278
252
279
/** A reference to the overlay when the calendar is opened as a popup. */
253
- _popupRef : OverlayRef ;
280
+ private _popupRef : OverlayRef | null ;
254
281
255
282
/** A reference to the dialog when the calendar is opened as a dialog. */
256
283
private _dialogRef : MatDialogRef < MatDatepickerContent < D > > | null ;
257
284
258
- /** A portal containing the calendar for this datepicker. */
259
- private _calendarPortal : ComponentPortal < MatDatepickerContent < D > > ;
260
-
261
285
/** Reference to the component instantiated in popup mode. */
262
286
private _popupComponentRef : ComponentRef < MatDatepickerContent < D > > | null ;
263
287
@@ -292,14 +316,10 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
292
316
}
293
317
294
318
ngOnDestroy ( ) {
319
+ this . _destroyPopup ( ) ;
295
320
this . close ( ) ;
296
321
this . _inputSubscription . unsubscribe ( ) ;
297
322
this . _disabledChange . complete ( ) ;
298
-
299
- if ( this . _popupRef ) {
300
- this . _popupRef . dispose ( ) ;
301
- this . _popupComponentRef = null ;
302
- }
303
323
}
304
324
305
325
/** Selects the given date */
@@ -356,16 +376,15 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
356
376
if ( ! this . _opened ) {
357
377
return ;
358
378
}
359
- if ( this . _popupRef && this . _popupRef . hasAttached ( ) ) {
360
- this . _popupRef . detach ( ) ;
379
+ if ( this . _popupComponentRef && this . _popupRef ) {
380
+ const instance = this . _popupComponentRef . instance ;
381
+ instance . _startExitAnimation ( ) ;
382
+ instance . _animationDone . pipe ( take ( 1 ) ) . subscribe ( ( ) => this . _destroyPopup ( ) ) ;
361
383
}
362
384
if ( this . _dialogRef ) {
363
385
this . _dialogRef . close ( ) ;
364
386
this . _dialogRef = null ;
365
387
}
366
- if ( this . _calendarPortal && this . _calendarPortal . isAttached ) {
367
- this . _calendarPortal . detach ( ) ;
368
- }
369
388
370
389
const completeClose = ( ) => {
371
390
// The `_opened` could've been reset already if
@@ -409,30 +428,24 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
409
428
410
429
this . _dialogRef . afterClosed ( ) . subscribe ( ( ) => this . close ( ) ) ;
411
430
this . _dialogRef . componentInstance . datepicker = this ;
412
- this . _setColor ( ) ;
431
+ this . _dialogRef . componentInstance . color = this . color ;
413
432
}
414
433
415
434
/** Open the calendar as a popup. */
416
435
private _openAsPopup ( ) : void {
417
- if ( ! this . _calendarPortal ) {
418
- this . _calendarPortal = new ComponentPortal < MatDatepickerContent < D > > ( MatDatepickerContent ,
419
- this . _viewContainerRef ) ;
420
- }
421
-
422
- if ( ! this . _popupRef ) {
423
- this . _createPopup ( ) ;
424
- }
425
-
426
- if ( ! this . _popupRef . hasAttached ( ) ) {
427
- this . _popupComponentRef = this . _popupRef . attach ( this . _calendarPortal ) ;
428
- this . _popupComponentRef . instance . datepicker = this ;
429
- this . _setColor ( ) ;
430
-
431
- // Update the position once the calendar has rendered.
432
- this . _ngZone . onStable . asObservable ( ) . pipe ( take ( 1 ) ) . subscribe ( ( ) => {
433
- this . _popupRef . updatePosition ( ) ;
434
- } ) ;
435
- }
436
+ const portal = new ComponentPortal < MatDatepickerContent < D > > ( MatDatepickerContent ,
437
+ this . _viewContainerRef ) ;
438
+
439
+ this . _destroyPopup ( ) ;
440
+ this . _createPopup ( ) ;
441
+ const ref = this . _popupComponentRef = this . _popupRef ! . attach ( portal ) ;
442
+ ref . instance . datepicker = this ;
443
+ ref . instance . color = this . color ;
444
+
445
+ // Update the position once the calendar has rendered.
446
+ this . _ngZone . onStable . asObservable ( ) . pipe ( take ( 1 ) ) . subscribe ( ( ) => {
447
+ this . _popupRef ! . updatePosition ( ) ;
448
+ } ) ;
436
449
}
437
450
438
451
/** Create the popup. */
@@ -466,6 +479,14 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
466
479
} ) ;
467
480
}
468
481
482
+ /** Destroys the current popup overlay. */
483
+ private _destroyPopup ( ) {
484
+ if ( this . _popupRef ) {
485
+ this . _popupRef . dispose ( ) ;
486
+ this . _popupRef = this . _popupComponentRef = null ;
487
+ }
488
+ }
489
+
469
490
/** Create the popup PositionStrategy. */
470
491
private _createPopupPositionStrategy ( ) : PositionStrategy {
471
492
return this . _overlay . position ( )
@@ -510,17 +531,6 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
510
531
return ( this . _dateAdapter . isDateInstance ( obj ) && this . _dateAdapter . isValid ( obj ) ) ? obj : null ;
511
532
}
512
533
513
- /** Passes the current theme color along to the calendar overlay. */
514
- private _setColor ( ) : void {
515
- const color = this . color ;
516
- if ( this . _popupComponentRef ) {
517
- this . _popupComponentRef . instance . color = color ;
518
- }
519
- if ( this . _dialogRef ) {
520
- this . _dialogRef . componentInstance . color = color ;
521
- }
522
- }
523
-
524
534
static ngAcceptInputType_disabled : BooleanInput ;
525
535
static ngAcceptInputType_touchUi : BooleanInput ;
526
536
}
0 commit comments