55
66import { Direction , Directionality } from '@angular/cdk/bidi' ;
77import { BACKSPACE , DOWN_ARROW , ENTER , ESCAPE , LEFT_ARROW , RIGHT_ARROW , UP_ARROW } from '@angular/cdk/keycodes' ;
8- import { CdkConnectedOverlay , ConnectionPositionPair , OverlayModule } from '@angular/cdk/overlay' ;
8+ import {
9+ CdkConnectedOverlay ,
10+ ConnectedOverlayPositionChange ,
11+ ConnectionPositionPair ,
12+ OverlayModule
13+ } from '@angular/cdk/overlay' ;
914import { _getEventTarget } from '@angular/cdk/platform' ;
1015import { SlicePipe } from '@angular/common' ;
1116import {
@@ -43,7 +48,13 @@ import { slideMotion } from 'ng-zorro-antd/core/animation';
4348import { NzConfigKey , NzConfigService , WithConfig } from 'ng-zorro-antd/core/config' ;
4449import { NzFormItemFeedbackIconComponent , NzFormNoStatusService , NzFormStatusService } from 'ng-zorro-antd/core/form' ;
4550import { NzNoAnimationDirective } from 'ng-zorro-antd/core/no-animation' ;
46- import { DEFAULT_CASCADER_POSITIONS , NzOverlayModule } from 'ng-zorro-antd/core/overlay' ;
51+ import {
52+ DEFAULT_CASCADER_POSITIONS ,
53+ getPlacementName ,
54+ NzOverlayModule ,
55+ POSITION_MAP ,
56+ POSITION_TYPE
57+ } from 'ng-zorro-antd/core/overlay' ;
4758import { NzDestroyService } from 'ng-zorro-antd/core/services' ;
4859import { NzTreeBase , NzTreeNode } from 'ng-zorro-antd/core/tree' ;
4960import {
@@ -62,6 +73,7 @@ import {
6273 NzSelectClearComponent ,
6374 NzSelectItemComponent ,
6475 NzSelectPlaceholderComponent ,
76+ NzSelectPlacementType ,
6577 NzSelectSearchComponent
6678} from 'ng-zorro-antd/select' ;
6779import { NZ_SPACE_COMPACT_ITEM_TYPE , NZ_SPACE_COMPACT_SIZE , NzSpaceCompactItemDirective } from 'ng-zorro-antd/space' ;
@@ -73,6 +85,7 @@ import {
7385 NzCascaderComponentAsSource ,
7486 NzCascaderExpandTrigger ,
7587 NzCascaderOption ,
88+ NzCascaderPlacement ,
7689 NzCascaderSize ,
7790 NzCascaderTriggerType ,
7891 NzShowSearchOptions
@@ -166,9 +179,14 @@ const defaultDisplayRender = (labels: string[]): string => labels.join(' / ');
166179 [cdkConnectedOverlayOpen]="menuVisible"
167180 (overlayOutsideClick)="onClickOutside($event)"
168181 (detach)="closeMenu()"
182+ (positionChange)="onPositionChange($event)"
169183 >
170184 <div
171- class="ant-select-dropdown ant-cascader-dropdown ant-select-dropdown-placement-bottomLeft"
185+ class="ant-select-dropdown ant-cascader-dropdown"
186+ [class.ant-select-dropdown-placement-bottomLeft]="dropdownPosition === 'bottomLeft'"
187+ [class.ant-select-dropdown-placement-bottomRight]="dropdownPosition === 'bottomRight'"
188+ [class.ant-select-dropdown-placement-topLeft]="dropdownPosition === 'topLeft'"
189+ [class.ant-select-dropdown-placement-topRight]="dropdownPosition === 'topRight'"
172190 [class.ant-cascader-dropdown-rtl]="dir === 'rtl'"
173191 [@slideMotion]="'enter'"
174192 [@.disabled]="!!noAnimation?.nzNoAnimation"
@@ -285,9 +303,11 @@ export class NzCascaderComponent
285303 set input ( inputComponent : NzSelectSearchComponent | undefined ) {
286304 this . input$ . next ( inputComponent ?. inputElement ) ;
287305 }
306+
288307 get input ( ) : ElementRef < HTMLInputElement > | undefined {
289308 return this . input$ . getValue ( ) ;
290309 }
310+
291311 /** Used to store the native `<input type="search" />` element since it might be set asynchronously. */
292312 private input$ = new BehaviorSubject < ElementRef < HTMLInputElement > | undefined > ( undefined ) ;
293313
@@ -327,6 +347,7 @@ export class NzCascaderComponent
327347 @Input ( ) nzStatus : NzStatus = '' ;
328348 @Input ( { transform : booleanAttribute } ) nzMultiple : boolean = false ;
329349 @Input ( ) nzMaxTagCount : number = Infinity ;
350+ @Input ( ) nzPlacement : NzCascaderPlacement = 'bottomLeft' ;
330351
331352 @Input ( ) nzTriggerAction : NzCascaderTriggerType | NzCascaderTriggerType [ ] = [ 'click' ] as NzCascaderTriggerType [ ] ;
332353 @Input ( ) nzChangeOn ?: ( option : NzCascaderOption , level : number ) => boolean ;
@@ -389,6 +410,7 @@ export class NzCascaderComponent
389410 */
390411 dropdownWidthStyle ?: string ;
391412 dropdownHeightStyle : 'auto' | '' = '' ;
413+ dropdownPosition : NzCascaderPlacement = 'bottomLeft' ;
392414 isFocused = false ;
393415
394416 locale ! : NzCascaderI18nInterface ;
@@ -551,13 +573,23 @@ export class NzCascaderComponent
551573 }
552574
553575 ngOnChanges ( changes : SimpleChanges ) : void {
554- const { nzStatus, nzSize } = changes ;
576+ const { nzStatus, nzSize, nzPlacement } = changes ;
555577 if ( nzStatus ) {
556578 this . setStatusStyles ( this . nzStatus , this . hasFeedback ) ;
557579 }
558580 if ( nzSize ) {
559581 this . size . set ( nzSize . currentValue ) ;
560582 }
583+ if ( nzPlacement ) {
584+ const { currentValue } = nzPlacement ;
585+ this . dropdownPosition = currentValue as NzCascaderPlacement ;
586+ const listOfPlacement = [ 'bottomLeft' , 'topLeft' , 'bottomRight' , 'topRight' ] ;
587+ if ( currentValue && listOfPlacement . includes ( currentValue ) ) {
588+ this . positions = [ POSITION_MAP [ currentValue as POSITION_TYPE ] ] ;
589+ } else {
590+ this . positions = listOfPlacement . map ( e => POSITION_MAP [ e as POSITION_TYPE ] ) ;
591+ }
592+ }
561593 }
562594
563595 ngOnDestroy ( ) : void {
@@ -939,6 +971,11 @@ export class NzCascaderComponent
939971 }
940972 }
941973
974+ onPositionChange ( position : ConnectedOverlayPositionChange ) : void {
975+ const placement = getPlacementName ( position ) ;
976+ this . dropdownPosition = placement as NzSelectPlacementType ;
977+ }
978+
942979 private isActionTrigger ( action : 'click' | 'hover' ) : boolean {
943980 return typeof this . nzTriggerAction === 'string'
944981 ? this . nzTriggerAction === action
0 commit comments