@@ -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 {
@@ -137,7 +145,7 @@ export class MatDatepickerContent<D> extends _MatDatepickerContentMixinBase
137
145
changeDetection : ChangeDetectionStrategy . OnPush ,
138
146
encapsulation : ViewEncapsulation . None ,
139
147
} )
140
- export class MatDatepicker < D > implements OnDestroy , CanColor {
148
+ export class MatDatepicker < D > implements OnDestroy , CanColor , OnChanges {
141
149
private _scrollStrategy : ( ) => ScrollStrategy ;
142
150
143
151
/** An input indicating the type of the custom header component for the calendar, if set. */
@@ -196,6 +204,14 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
196
204
}
197
205
private _disabled : boolean ;
198
206
207
+ /** Position of the datepicker in the X axis. */
208
+ @Input ( )
209
+ xPosition : DatepickerDropdownPositionX = 'start' ;
210
+
211
+ /** Position of the datepicker in the Y axis. */
212
+ @Input ( )
213
+ yPosition : DatepickerDropdownPositionY = 'below' ;
214
+
199
215
/**
200
216
* Emits selected year in multiyear view.
201
217
* This doesn't imply a change on the selected date.
@@ -291,6 +307,19 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
291
307
this . _scrollStrategy = scrollStrategy ;
292
308
}
293
309
310
+ ngOnChanges ( changes : SimpleChanges ) {
311
+ const positionChange = changes [ 'xPosition' ] || changes [ 'yPosition' ] ;
312
+
313
+ if ( positionChange && ! positionChange . firstChange && this . _popupRef ) {
314
+ this . _setConnectedPositions (
315
+ this . _popupRef . getConfig ( ) . positionStrategy as FlexibleConnectedPositionStrategy ) ;
316
+
317
+ if ( this . opened ) {
318
+ this . _popupRef . updatePosition ( ) ;
319
+ }
320
+ }
321
+ }
322
+
294
323
ngOnDestroy ( ) {
295
324
this . close ( ) ;
296
325
this . _inputSubscription . unsubscribe ( ) ;
@@ -437,8 +466,15 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
437
466
438
467
/** Create the popup. */
439
468
private _createPopup ( ) : void {
469
+ const positionStrategy = this . _overlay . position ( )
470
+ . flexibleConnectedTo ( this . _datepickerInput . getConnectedOverlayOrigin ( ) )
471
+ . withTransformOriginOn ( '.mat-datepicker-content' )
472
+ . withFlexibleDimensions ( false )
473
+ . withViewportMargin ( 8 )
474
+ . withLockedPosition ( ) ;
475
+
440
476
const overlayConfig = new OverlayConfig ( {
441
- positionStrategy : this . _createPopupPositionStrategy ( ) ,
477
+ positionStrategy : this . _setConnectedPositions ( positionStrategy ) ,
442
478
hasBackdrop : true ,
443
479
backdropClass : 'mat-overlay-transparent-backdrop' ,
444
480
direction : this . _dir ,
@@ -466,40 +502,39 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
466
502
} ) ;
467
503
}
468
504
469
- /** Create the popup PositionStrategy. */
470
- private _createPopupPositionStrategy ( ) : PositionStrategy {
471
- return this . _overlay . position ( )
472
- . flexibleConnectedTo ( this . _datepickerInput . getConnectedOverlayOrigin ( ) )
473
- . withTransformOriginOn ( '.mat-datepicker-content' )
474
- . withFlexibleDimensions ( false )
475
- . withViewportMargin ( 8 )
476
- . withLockedPosition ( )
477
- . withPositions ( [
478
- {
479
- originX : 'start' ,
480
- originY : 'bottom' ,
481
- overlayX : 'start' ,
482
- overlayY : 'top'
483
- } ,
484
- {
485
- originX : 'start' ,
486
- originY : 'top' ,
487
- overlayX : 'start' ,
488
- overlayY : 'bottom'
489
- } ,
490
- {
491
- originX : 'end' ,
492
- originY : 'bottom' ,
493
- overlayX : 'end' ,
494
- overlayY : 'top'
495
- } ,
496
- {
497
- originX : 'end' ,
498
- originY : 'top' ,
499
- overlayX : 'end' ,
500
- overlayY : 'bottom'
501
- }
502
- ] ) ;
505
+ /** Sets the positions of the datepicker in dropdown mode based on the current configuration. */
506
+ private _setConnectedPositions ( strategy : FlexibleConnectedPositionStrategy ) {
507
+ const primaryX = this . xPosition === 'end' ? 'end' : 'start' ;
508
+ const secondaryX = primaryX === 'start' ? 'end' : 'start' ;
509
+ const primaryY = this . yPosition === 'above' ? 'bottom' : 'top' ;
510
+ const secondaryY = primaryY === 'top' ? 'bottom' : 'top' ;
511
+
512
+ return strategy . withPositions ( [
513
+ {
514
+ originX : primaryX ,
515
+ originY : secondaryY ,
516
+ overlayX : primaryX ,
517
+ overlayY : primaryY
518
+ } ,
519
+ {
520
+ originX : primaryX ,
521
+ originY : primaryY ,
522
+ overlayX : primaryX ,
523
+ overlayY : secondaryY
524
+ } ,
525
+ {
526
+ originX : secondaryX ,
527
+ originY : secondaryY ,
528
+ overlayX : secondaryX ,
529
+ overlayY : primaryY
530
+ } ,
531
+ {
532
+ originX : secondaryX ,
533
+ originY : primaryY ,
534
+ overlayX : secondaryX ,
535
+ overlayY : secondaryY
536
+ }
537
+ ] ) ;
503
538
}
504
539
505
540
/**
0 commit comments