@@ -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' ;
@@ -36,6 +36,8 @@ import {
36
36
ViewContainerRef ,
37
37
ViewEncapsulation ,
38
38
ChangeDetectorRef ,
39
+ OnChanges ,
40
+ SimpleChanges ,
39
41
} from '@angular/core' ;
40
42
import {
41
43
CanColor ,
@@ -72,6 +74,12 @@ export const MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER = {
72
74
useFactory : MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY ,
73
75
} ;
74
76
77
+ /** Possible positions for the datepicker dropdown along the X axis. */
78
+ export type DatepickerDropdownPositionX = 'start' | 'end' ;
79
+
80
+ /** Possible positions for the datepicker dropdown along the Y axis. */
81
+ export type DatepickerDropdownPositionY = 'above' | 'below' ;
82
+
75
83
// Boilerplate for applying mixins to MatDatepickerContent.
76
84
/** @docs -private */
77
85
class MatDatepickerContentBase {
@@ -164,7 +172,7 @@ export class MatDatepickerContent<D> extends _MatDatepickerContentMixinBase
164
172
changeDetection : ChangeDetectionStrategy . OnPush ,
165
173
encapsulation : ViewEncapsulation . None ,
166
174
} )
167
- export class MatDatepicker < D > implements OnDestroy , CanColor {
175
+ export class MatDatepicker < D > implements OnDestroy , CanColor , OnChanges {
168
176
private _scrollStrategy : ( ) => ScrollStrategy ;
169
177
170
178
/** An input indicating the type of the custom header component for the calendar, if set. */
@@ -223,6 +231,14 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
223
231
}
224
232
private _disabled : boolean ;
225
233
234
+ /** Preferred position of the datepicker in the X axis. */
235
+ @Input ( )
236
+ xPosition : DatepickerDropdownPositionX = 'start' ;
237
+
238
+ /** Preferred position of the datepicker in the Y axis. */
239
+ @Input ( )
240
+ yPosition : DatepickerDropdownPositionY = 'below' ;
241
+
226
242
/**
227
243
* Emits selected year in multiyear view.
228
244
* This doesn't imply a change on the selected date.
@@ -315,6 +331,19 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
315
331
this . _scrollStrategy = scrollStrategy ;
316
332
}
317
333
334
+ ngOnChanges ( changes : SimpleChanges ) {
335
+ const positionChange = changes [ 'xPosition' ] || changes [ 'yPosition' ] ;
336
+
337
+ if ( positionChange && ! positionChange . firstChange && this . _popupRef ) {
338
+ this . _setConnectedPositions (
339
+ this . _popupRef . getConfig ( ) . positionStrategy as FlexibleConnectedPositionStrategy ) ;
340
+
341
+ if ( this . opened ) {
342
+ this . _popupRef . updatePosition ( ) ;
343
+ }
344
+ }
345
+ }
346
+
318
347
ngOnDestroy ( ) {
319
348
this . _destroyPopup ( ) ;
320
349
this . close ( ) ;
@@ -464,8 +493,15 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
464
493
465
494
/** Create the popup. */
466
495
private _createPopup ( ) : void {
496
+ const positionStrategy = this . _overlay . position ( )
497
+ . flexibleConnectedTo ( this . _datepickerInput . getConnectedOverlayOrigin ( ) )
498
+ . withTransformOriginOn ( '.mat-datepicker-content' )
499
+ . withFlexibleDimensions ( false )
500
+ . withViewportMargin ( 8 )
501
+ . withLockedPosition ( ) ;
502
+
467
503
const overlayConfig = new OverlayConfig ( {
468
- positionStrategy : this . _createPopupPositionStrategy ( ) ,
504
+ positionStrategy : this . _setConnectedPositions ( positionStrategy ) ,
469
505
hasBackdrop : true ,
470
506
backdropClass : 'mat-overlay-transparent-backdrop' ,
471
507
direction : this . _dir ,
@@ -501,40 +537,39 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
501
537
}
502
538
}
503
539
504
- /** Create the popup PositionStrategy. */
505
- private _createPopupPositionStrategy ( ) : PositionStrategy {
506
- return this . _overlay . position ( )
507
- . flexibleConnectedTo ( this . _datepickerInput . getConnectedOverlayOrigin ( ) )
508
- . withTransformOriginOn ( '.mat-datepicker-content' )
509
- . withFlexibleDimensions ( false )
510
- . withViewportMargin ( 8 )
511
- . withLockedPosition ( )
512
- . withPositions ( [
513
- {
514
- originX : 'start' ,
515
- originY : 'bottom' ,
516
- overlayX : 'start' ,
517
- overlayY : 'top'
518
- } ,
519
- {
520
- originX : 'start' ,
521
- originY : 'top' ,
522
- overlayX : 'start' ,
523
- overlayY : 'bottom'
524
- } ,
525
- {
526
- originX : 'end' ,
527
- originY : 'bottom' ,
528
- overlayX : 'end' ,
529
- overlayY : 'top'
530
- } ,
531
- {
532
- originX : 'end' ,
533
- originY : 'top' ,
534
- overlayX : 'end' ,
535
- overlayY : 'bottom'
536
- }
537
- ] ) ;
540
+ /** Sets the positions of the datepicker in dropdown mode based on the current configuration. */
541
+ private _setConnectedPositions ( strategy : FlexibleConnectedPositionStrategy ) {
542
+ const primaryX = this . xPosition === 'end' ? 'end' : 'start' ;
543
+ const secondaryX = primaryX === 'start' ? 'end' : 'start' ;
544
+ const primaryY = this . yPosition === 'above' ? 'bottom' : 'top' ;
545
+ const secondaryY = primaryY === 'top' ? 'bottom' : 'top' ;
546
+
547
+ return strategy . withPositions ( [
548
+ {
549
+ originX : primaryX ,
550
+ originY : secondaryY ,
551
+ overlayX : primaryX ,
552
+ overlayY : primaryY
553
+ } ,
554
+ {
555
+ originX : primaryX ,
556
+ originY : primaryY ,
557
+ overlayX : primaryX ,
558
+ overlayY : secondaryY
559
+ } ,
560
+ {
561
+ originX : secondaryX ,
562
+ originY : secondaryY ,
563
+ overlayX : secondaryX ,
564
+ overlayY : primaryY
565
+ } ,
566
+ {
567
+ originX : secondaryX ,
568
+ originY : primaryY ,
569
+ overlayX : secondaryX ,
570
+ overlayY : secondaryY
571
+ }
572
+ ] ) ;
538
573
}
539
574
540
575
/**
0 commit comments