diff --git a/components/cascader/cascader.component.ts b/components/cascader/cascader.component.ts index f2ae6654bd4..3c82b9941b7 100644 --- a/components/cascader/cascader.component.ts +++ b/components/cascader/cascader.component.ts @@ -734,6 +734,7 @@ export class NzCascaderComponent const options = this.cascaderService.activatedOptions; if (options.length) { options.pop(); // Remove the last one + this.cascaderService.setOptionDeactivatedSinceColumn(options.length); // collapse menu } } @@ -790,6 +791,10 @@ export class NzCascaderComponent this.blur(); this.clearDelayMenuTimer(); this.setMenuVisible(false); + // if select none, clear previous state + if (!this.hasValue && this.cascaderService.columns.length) { + this.cascaderService.dropBehindColumns(0); + } } /** diff --git a/components/cascader/cascader.service.ts b/components/cascader/cascader.service.ts index 9a7179b4cd2..67587f6b9ed 100644 --- a/components/cascader/cascader.service.ts +++ b/components/cascader/cascader.service.ts @@ -358,8 +358,8 @@ export class NzCascaderService implements OnDestroy { if (!arraysEqual(existingOptions, options)) { options.forEach(o => (o.parent = parent)); this.columns[columnIndex] = options; - this.dropBehindColumns(columnIndex); } + this.dropBehindColumns(columnIndex); } /** @@ -377,7 +377,7 @@ export class NzCascaderService implements OnDestroy { this.activatedOptions = this.activatedOptions.splice(0, lastReserveIndex + 1); } - private dropBehindColumns(lastReserveIndex: number): void { + dropBehindColumns(lastReserveIndex: number): void { if (lastReserveIndex < this.columns.length - 1) { this.columns = this.columns.slice(0, lastReserveIndex + 1); } diff --git a/components/cascader/cascader.spec.ts b/components/cascader/cascader.spec.ts index bc86c3b1b79..89e5f377a6f 100644 --- a/components/cascader/cascader.spec.ts +++ b/components/cascader/cascader.spec.ts @@ -27,6 +27,7 @@ import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { createFakeEvent, createMouseEvent, + dispatchFakeEvent, dispatchKeyboardEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing'; @@ -741,9 +742,9 @@ describe('cascader', () => { expect(testComponent.cascader.menuVisible).toBe(true); expect(getAllColumns().length).toBe(3); - const itemEl1 = getItemAtColumnAndRow(1, 1)!; - const itemEl2 = getItemAtColumnAndRow(2, 1)!; - const itemEl3 = getItemAtColumnAndRow(3, 1)!; + let itemEl1 = getItemAtColumnAndRow(1, 1)!; + let itemEl2 = getItemAtColumnAndRow(2, 1)!; + let itemEl3 = getItemAtColumnAndRow(3, 1)!; expect(itemEl1.classList).toContain('ant-cascader-menu-item-active'); expect(itemEl2.classList).toContain('ant-cascader-menu-item-active'); @@ -755,14 +756,17 @@ describe('cascader', () => { fixture.detectChanges(); dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW); fixture.detectChanges(); - expect(getAllColumns().length).toBe(3); + itemEl1 = getItemAtColumnAndRow(1, 1)!; + itemEl2 = getItemAtColumnAndRow(2, 1)!; + itemEl3 = getItemAtColumnAndRow(3, 1)!; expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active'); - expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active'); - expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active'); + expect(itemEl2).toBeNull(); + expect(itemEl3).toBeNull(); + expect(getAllColumns().length).toBe(1); expect(testComponent.values!.join(',')).toBe('zhejiang,hangzhou,xihu'); + itemEl1.click(); const itemEl4 = getItemAtColumnAndRow(2, 2)!; - itemEl4.click(); // 选中一个叶子 fixture.detectChanges(); tick(300); @@ -870,6 +874,44 @@ describe('cascader', () => { expect(testComponent.cascader.menuVisible).toBe(false); })); + it('should init menu when selecting cancel', fakeAsync(() => { + // cancel select by ESCAPE + fixture.detectChanges(); + testComponent.cascader.setMenuVisible(true); + let itemEl1 = getItemAtColumnAndRow(1, 1)!; + itemEl1.click(); + let itemEl2 = getItemAtColumnAndRow(2, 1)!; + itemEl2.click(); + let itemEl3 = getItemAtColumnAndRow(3, 1)!; + expect(itemEl1.classList).toContain('ant-cascader-menu-item-active'); + expect(itemEl2.classList).toContain('ant-cascader-menu-item-active'); + expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active'); + dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ESCAPE); + fixture.detectChanges(); + flush(); + fixture.detectChanges(); + expect(testComponent.cascader.menuVisible).toBe(false); + expect(testComponent.cascader.cascaderService.columns.length).toBe(1); + + // cancel select by clicking outside + fixture.detectChanges(); + testComponent.cascader.setMenuVisible(true); + itemEl1 = getItemAtColumnAndRow(1, 1)!; + itemEl1.click(); + itemEl2 = getItemAtColumnAndRow(2, 1)!; + itemEl2.click(); + itemEl3 = getItemAtColumnAndRow(3, 1)!; + expect(itemEl1.classList).toContain('ant-cascader-menu-item-active'); + expect(itemEl2.classList).toContain('ant-cascader-menu-item-active'); + expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active'); + dispatchFakeEvent(document.body, 'click'); + fixture.detectChanges(); + flush(); + fixture.detectChanges(); + expect(testComponent.cascader.menuVisible).toBe(false); + expect(testComponent.cascader.cascaderService.columns.length).toBe(1); + })); + it('should nzBackdrop works', fakeAsync(() => { testComponent.nzBackdrop = true; fixture.detectChanges(); @@ -941,9 +983,9 @@ describe('cascader', () => { fixture.detectChanges(); expect(getAllColumns().length).toBe(3); - const itemEl1 = getItemAtColumnAndRow(1, 1)!; - const itemEl2 = getItemAtColumnAndRow(2, 1)!; - const itemEl3 = getItemAtColumnAndRow(3, 1)!; + let itemEl1 = getItemAtColumnAndRow(1, 1)!; + let itemEl2 = getItemAtColumnAndRow(2, 1)!; + let itemEl3 = getItemAtColumnAndRow(3, 1)!; expect(itemEl1.classList).toContain('ant-cascader-menu-item-active'); expect(itemEl2.classList).toContain('ant-cascader-menu-item-active'); expect(itemEl3.classList).toContain('ant-cascader-menu-item-active'); @@ -954,14 +996,17 @@ describe('cascader', () => { expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active'); dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW); fixture.detectChanges(); + itemEl3 = getItemAtColumnAndRow(3, 1)!; expect(itemEl1.classList).toContain('ant-cascader-menu-item-active'); expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active'); - expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active'); + expect(itemEl3).toBeNull(); + expect(getAllColumns().length).toBe(2); dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW); fixture.detectChanges(); + itemEl2 = getItemAtColumnAndRow(2, 1)!; expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active'); - expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active'); - expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active'); + expect(itemEl2).toBeNull(); + expect(getAllColumns().length).toBe(1); })); it('should select option when press ENTER', fakeAsync(() => {