@@ -13,8 +13,8 @@ import {
13
13
Overlay ,
14
14
OverlayConfig ,
15
15
OverlayRef ,
16
- PositionStrategy ,
17
16
ScrollStrategy ,
17
+ FlexibleConnectedPositionStrategy ,
18
18
} from '@angular/cdk/overlay' ;
19
19
import { ComponentPortal , ComponentType } from '@angular/cdk/portal' ;
20
20
import { DOCUMENT } from '@angular/common' ;
@@ -35,6 +35,8 @@ import {
35
35
ViewChild ,
36
36
ViewContainerRef ,
37
37
ViewEncapsulation ,
38
+ OnChanges ,
39
+ SimpleChanges ,
38
40
} from '@angular/core' ;
39
41
import {
40
42
CanColor ,
@@ -71,6 +73,12 @@ export const MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER = {
71
73
useFactory : MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY ,
72
74
} ;
73
75
76
+ /** Possible positions for the datepicker dropdown along the X axis. */
77
+ export type DatepickerDropdownPositionX = 'start' | 'end' ;
78
+
79
+ /** Possible positions for the datepicker dropdown along the Y axis. */
80
+ export type DatepickerDropdownPositionY = 'above' | 'below' ;
81
+
74
82
// Boilerplate for applying mixins to MatDatepickerContent.
75
83
/** @docs -private */
76
84
class MatDatepickerContentBase {
@@ -139,7 +147,7 @@ export class MatDatepickerContent<D> extends _MatDatepickerContentMixinBase
139
147
changeDetection : ChangeDetectionStrategy . OnPush ,
140
148
encapsulation : ViewEncapsulation . None ,
141
149
} )
142
- export class MatDatepicker < D > implements OnDestroy , CanColor {
150
+ export class MatDatepicker < D > implements OnDestroy , CanColor , OnChanges {
143
151
private _scrollStrategy : ( ) => ScrollStrategy ;
144
152
145
153
/** An input indicating the type of the custom header component for the calendar, if set. */
@@ -198,6 +206,14 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
198
206
}
199
207
private _disabled : boolean ;
200
208
209
+ /** Position of the datepicker in the X axis. */
210
+ @Input ( )
211
+ xPosition : DatepickerDropdownPositionX = 'start' ;
212
+
213
+ /** Position of the datepicker in the Y axis. */
214
+ @Input ( )
215
+ yPosition : DatepickerDropdownPositionY = 'below' ;
216
+
201
217
/**
202
218
* Emits selected year in multiyear view.
203
219
* This doesn't imply a change on the selected date.
@@ -293,6 +309,19 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
293
309
this . _scrollStrategy = scrollStrategy ;
294
310
}
295
311
312
+ ngOnChanges ( changes : SimpleChanges ) {
313
+ const positionChange = changes [ 'xPosition' ] || changes [ 'yPosition' ] ;
314
+
315
+ if ( positionChange && ! positionChange . firstChange && this . _popupRef ) {
316
+ this . _setConnectedPositions (
317
+ this . _popupRef . getConfig ( ) . positionStrategy as FlexibleConnectedPositionStrategy ) ;
318
+
319
+ if ( this . opened ) {
320
+ this . _popupRef . updatePosition ( ) ;
321
+ }
322
+ }
323
+ }
324
+
296
325
ngOnDestroy ( ) {
297
326
this . close ( ) ;
298
327
this . _inputSubscription . unsubscribe ( ) ;
@@ -439,8 +468,15 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
439
468
440
469
/** Create the popup. */
441
470
private _createPopup ( ) : void {
471
+ const positionStrategy = this . _overlay . position ( )
472
+ . flexibleConnectedTo ( this . _datepickerInput . getConnectedOverlayOrigin ( ) )
473
+ . withTransformOriginOn ( '.mat-datepicker-content' )
474
+ . withFlexibleDimensions ( false )
475
+ . withViewportMargin ( 8 )
476
+ . withLockedPosition ( ) ;
477
+
442
478
const overlayConfig = new OverlayConfig ( {
443
- positionStrategy : this . _createPopupPositionStrategy ( ) ,
479
+ positionStrategy : this . _setConnectedPositions ( positionStrategy ) ,
444
480
hasBackdrop : true ,
445
481
backdropClass : 'mat-overlay-transparent-backdrop' ,
446
482
direction : this . _dir ,
@@ -468,40 +504,39 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
468
504
} ) ;
469
505
}
470
506
471
- /** Create the popup PositionStrategy. */
472
- private _createPopupPositionStrategy ( ) : PositionStrategy {
473
- return this . _overlay . position ( )
474
- . flexibleConnectedTo ( this . _datepickerInput . getConnectedOverlayOrigin ( ) )
475
- . withTransformOriginOn ( '.mat-datepicker-content' )
476
- . withFlexibleDimensions ( false )
477
- . withViewportMargin ( 8 )
478
- . withLockedPosition ( )
479
- . withPositions ( [
480
- {
481
- originX : 'start' ,
482
- originY : 'bottom' ,
483
- overlayX : 'start' ,
484
- overlayY : 'top'
485
- } ,
486
- {
487
- originX : 'start' ,
488
- originY : 'top' ,
489
- overlayX : 'start' ,
490
- overlayY : 'bottom'
491
- } ,
492
- {
493
- originX : 'end' ,
494
- originY : 'bottom' ,
495
- overlayX : 'end' ,
496
- overlayY : 'top'
497
- } ,
498
- {
499
- originX : 'end' ,
500
- originY : 'top' ,
501
- overlayX : 'end' ,
502
- overlayY : 'bottom'
503
- }
504
- ] ) ;
507
+ /** Sets the positions of the datepicker in dropdown mode based on the current configuration. */
508
+ private _setConnectedPositions ( strategy : FlexibleConnectedPositionStrategy ) {
509
+ const primaryX = this . xPosition === 'end' ? 'end' : 'start' ;
510
+ const secondaryX = primaryX === 'start' ? 'end' : 'start' ;
511
+ const primaryY = this . yPosition === 'above' ? 'bottom' : 'top' ;
512
+ const secondaryY = primaryY === 'top' ? 'bottom' : 'top' ;
513
+
514
+ return strategy . withPositions ( [
515
+ {
516
+ originX : primaryX ,
517
+ originY : secondaryY ,
518
+ overlayX : primaryX ,
519
+ overlayY : primaryY
520
+ } ,
521
+ {
522
+ originX : primaryX ,
523
+ originY : primaryY ,
524
+ overlayX : primaryX ,
525
+ overlayY : secondaryY
526
+ } ,
527
+ {
528
+ originX : secondaryX ,
529
+ originY : secondaryY ,
530
+ overlayX : secondaryX ,
531
+ overlayY : primaryY
532
+ } ,
533
+ {
534
+ originX : secondaryX ,
535
+ originY : primaryY ,
536
+ overlayX : secondaryX ,
537
+ overlayY : secondaryY
538
+ }
539
+ ] ) ;
505
540
}
506
541
507
542
/**
0 commit comments