diff --git a/components/select/select.component.ts b/components/select/select.component.ts index 0e04ff49933..cfbece51342 100644 --- a/components/select/select.component.ts +++ b/components/select/select.component.ts @@ -115,6 +115,7 @@ export type NzSelectSizeType = 'large' | 'default' | 'small'; [cdkConnectedOverlayTransformOriginOn]="'.ant-select-dropdown'" [cdkConnectedOverlayPanelClass]="nzDropdownClassName!" [cdkConnectedOverlayOpen]="nzOpen" + (overlayKeydown)="onOverlayKeyDown($event)" (overlayOutsideClick)="onClickOutside($event)" (detach)="setOpenState(false)" (positionChange)="onPositionChange($event)" @@ -368,6 +369,12 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterVie this.clearInput(); } + onOverlayKeyDown(e: KeyboardEvent): void { + if (e.keyCode === ESCAPE) { + this.setOpenState(false); + } + } + onKeyDown(e: KeyboardEvent): void { if (this.nzDisabled) { return; @@ -411,7 +418,9 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterVie this.setOpenState(false); break; case ESCAPE: - this.setOpenState(false); + /** + * Skip the ESCAPE processing, it will be handled in {@link onOverlayKeyDown}. + */ break; default: if (!this.nzOpen) { diff --git a/components/select/select.spec.ts b/components/select/select.spec.ts index 1912567de1c..27d5bd18699 100644 --- a/components/select/select.spec.ts +++ b/components/select/select.spec.ts @@ -1,6 +1,7 @@ -import { BACKSPACE, DOWN_ARROW, ENTER, SPACE, TAB, UP_ARROW } from '@angular/cdk/keycodes'; +import { BACKSPACE, DOWN_ARROW, ENTER, ESCAPE, SPACE, TAB, UP_ARROW } from '@angular/cdk/keycodes'; +import { OverlayContainer } from '@angular/cdk/overlay'; import { Component, TemplateRef, ViewChild } from '@angular/core'; -import { ComponentFixture, fakeAsync, flush } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, flush, inject } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { @@ -22,12 +23,19 @@ describe('select', () => { let component: TestSelectTemplateDefaultComponent; let fixture: ComponentFixture; let selectElement!: HTMLElement; + let overlayContainerElement: HTMLElement; + beforeEach(() => { testBed = createComponentBed(TestSelectTemplateDefaultComponent, { imports: [NzSelectModule, NzIconTestModule, FormsModule] }); component = testBed.component; fixture = testBed.fixture; selectElement = testBed.debugElement.query(By.directive(NzSelectComponent)).nativeElement; }); + + beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => { + overlayContainerElement = oc.getContainerElement(); + })); + it('should classname correct', () => { expect(selectElement.classList).toContain('ant-select'); expect(selectElement.classList).toContain('ant-select-single'); @@ -255,6 +263,22 @@ describe('select', () => { expect(selectElement.classList).toContain('ant-select-disabled'); expect(selectElement.querySelector('input')!.getAttribute('disabled')).toBe(''); })); + + it('should close dropdown when ESC keydown', fakeAsync(() => { + component.nzOpen = true; + fixture.detectChanges(); + flush(); + fixture.detectChanges(); + + dispatchKeyboardEvent(overlayContainerElement, 'keydown', ESCAPE, overlayContainerElement); + + fixture.detectChanges(); + flush(); + fixture.detectChanges(); + + expect(component.nzOpen).toBe(false); + })); + it('should keydown up arrow and down arrow', fakeAsync(() => { const flushChanges = () => { fixture.detectChanges();