@@ -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 ( ) ;
@@ -471,8 +500,15 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
471
500
472
501
/** Create the popup. */
473
502
private _createPopup ( ) : void {
503
+ const positionStrategy = this . _overlay . position ( )
504
+ . flexibleConnectedTo ( this . _datepickerInput . getConnectedOverlayOrigin ( ) )
505
+ . withTransformOriginOn ( '.mat-datepicker-content' )
506
+ . withFlexibleDimensions ( false )
507
+ . withViewportMargin ( 8 )
508
+ . withLockedPosition ( ) ;
509
+
474
510
const overlayConfig = new OverlayConfig ( {
475
- positionStrategy : this . _createPopupPositionStrategy ( ) ,
511
+ positionStrategy : this . _setConnectedPositions ( positionStrategy ) ,
476
512
hasBackdrop : true ,
477
513
backdropClass : 'mat-overlay-transparent-backdrop' ,
478
514
direction : this . _dir ,
@@ -508,40 +544,39 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
508
544
}
509
545
}
510
546
511
- /** Create the popup PositionStrategy. */
512
- private _createPopupPositionStrategy ( ) : PositionStrategy {
513
- return this . _overlay . position ( )
514
- . flexibleConnectedTo ( this . _datepickerInput . getConnectedOverlayOrigin ( ) )
515
- . withTransformOriginOn ( '.mat-datepicker-content' )
516
- . withFlexibleDimensions ( false )
517
- . withViewportMargin ( 8 )
518
- . withLockedPosition ( )
519
- . withPositions ( [
520
- {
521
- originX : 'start' ,
522
- originY : 'bottom' ,
523
- overlayX : 'start' ,
524
- overlayY : 'top'
525
- } ,
526
- {
527
- originX : 'start' ,
528
- originY : 'top' ,
529
- overlayX : 'start' ,
530
- overlayY : 'bottom'
531
- } ,
532
- {
533
- originX : 'end' ,
534
- originY : 'bottom' ,
535
- overlayX : 'end' ,
536
- overlayY : 'top'
537
- } ,
538
- {
539
- originX : 'end' ,
540
- originY : 'top' ,
541
- overlayX : 'end' ,
542
- overlayY : 'bottom'
543
- }
544
- ] ) ;
547
+ /** Sets the positions of the datepicker in dropdown mode based on the current configuration. */
548
+ private _setConnectedPositions ( strategy : FlexibleConnectedPositionStrategy ) {
549
+ const primaryX = this . xPosition === 'end' ? 'end' : 'start' ;
550
+ const secondaryX = primaryX === 'start' ? 'end' : 'start' ;
551
+ const primaryY = this . yPosition === 'above' ? 'bottom' : 'top' ;
552
+ const secondaryY = primaryY === 'top' ? 'bottom' : 'top' ;
553
+
554
+ return strategy . withPositions ( [
555
+ {
556
+ originX : primaryX ,
557
+ originY : secondaryY ,
558
+ overlayX : primaryX ,
559
+ overlayY : primaryY
560
+ } ,
561
+ {
562
+ originX : primaryX ,
563
+ originY : primaryY ,
564
+ overlayX : primaryX ,
565
+ overlayY : secondaryY
566
+ } ,
567
+ {
568
+ originX : secondaryX ,
569
+ originY : secondaryY ,
570
+ overlayX : secondaryX ,
571
+ overlayY : primaryY
572
+ } ,
573
+ {
574
+ originX : secondaryX ,
575
+ originY : primaryY ,
576
+ overlayX : secondaryX ,
577
+ overlayY : secondaryY
578
+ }
579
+ ] ) ;
545
580
}
546
581
547
582
/**
0 commit comments