Skip to content

Commit

Permalink
refactor(module:autocomplete): refactor and sync Ant Design 4 (#4661)
Browse files Browse the repository at this point in the history
ref #4634
  • Loading branch information
hsuanxyz authored Mar 6, 2020
1 parent 4f7e836 commit 5bec1ff
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulati
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
templateUrl: './nz-autocomplete-optgroup.component.html',
host: {
role: 'group',
class: 'ant-select-dropdown-menu-item-group'
}
template: `
<div class="ant-select-item ant-select-item-group">
<ng-container *nzStringTemplateOutlet="nzLabel">{{ nzLabel }}</ng-container>
</div>
<ng-content select="nz-auto-option"></ng-content>
`
})
export class NzAutocompleteOptgroupComponent {
@Input() nzLabel: string | TemplateRef<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import {
ElementRef,
EventEmitter,
Input,
Optional,
Output,
ViewEncapsulation
} from '@angular/core';

import { InputBoolean, scrollIntoView } from 'ng-zorro-antd/core';

import { NzAutocompleteOptgroupComponent } from './autocomplete-optgroup.component';

export class NzOptionSelectionChange {
constructor(public source: NzAutocompleteOptionComponent, public isUserInput: boolean = false) {}
}
Expand All @@ -29,16 +32,22 @@ export class NzOptionSelectionChange {
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
templateUrl: './nz-autocomplete-option.component.html',
template: `
<div class="ant-select-item-option-content">
<ng-content></ng-content>
</div>
`,
host: {
role: 'menuitem',
class: 'ant-select-dropdown-menu-item',
'[class.ant-select-dropdown-menu-item-selected]': 'selected',
'[class.ant-select-dropdown-menu-item-active]': 'active',
'[class.ant-select-dropdown-menu-item-disabled]': 'nzDisabled',
class: 'ant-select-item ant-select-item-option',
'[class.ant-select-item-option-grouped]': 'nzAutocompleteOptgroupComponent',
'[class.ant-select-item-option-selected]': 'selected',
'[class.ant-select-item-option-active]': 'active',
'[class.ant-select-item-option-disabled]': 'nzDisabled',
'[attr.aria-selected]': 'selected.toString()',
'[attr.aria-disabled]': 'nzDisabled.toString()',
'(click)': 'selectViaInteraction()',
'(mouseenter)': 'onMouseEnter()',
'(mousedown)': '$event.preventDefault()'
}
})
Expand All @@ -48,11 +57,17 @@ export class NzAutocompleteOptionComponent {
@Input() nzLabel: string;
@Input() @InputBoolean() nzDisabled = false;
@Output() readonly selectionChange = new EventEmitter<NzOptionSelectionChange>();
@Output() readonly mouseEntered = new EventEmitter<NzAutocompleteOptionComponent>();

active = false;
selected = false;

constructor(private changeDetectorRef: ChangeDetectorRef, private element: ElementRef) {}
constructor(
private changeDetectorRef: ChangeDetectorRef,
private element: ElementRef,
@Optional()
public nzAutocompleteOptgroupComponent: NzAutocompleteOptgroupComponent
) {}

select(emit: boolean = true): void {
this.selected = true;
Expand All @@ -62,6 +77,10 @@ export class NzAutocompleteOptionComponent {
}
}

onMouseEnter(): void {
this.mouseEntered.emit(this);
}

deselect(): void {
this.selected = false;
this.changeDetectorRef.markForCheck();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { fromEvent, merge, Subscription } from 'rxjs';
import { delay, distinct, map, take, tap } from 'rxjs/operators';

import { NzAutocompleteOptionComponent } from './nz-autocomplete-option.component';
import { NzAutocompleteComponent } from './nz-autocomplete.component';
import { NzAutocompleteOptionComponent } from './autocomplete-option.component';
import { NzAutocompleteComponent } from './autocomplete.component';

export const NZ_AUTOCOMPLETE_VALUE_ACCESSOR: ExistingProvider = {
provide: NG_VALUE_ACCESSOR,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { filter, switchMap, take } from 'rxjs/operators';

import { CompareWith, InputBoolean, NzDropDownPosition, NzNoAnimationDirective, slideMotion } from 'ng-zorro-antd/core';

import { NzAutocompleteOptionComponent, NzOptionSelectionChange } from './nz-autocomplete-option.component';
import { NzAutocompleteOptionComponent, NzOptionSelectionChange } from './autocomplete-option.component';

export interface AutocompleteDataSourceItem {
value: string;
Expand All @@ -47,17 +47,37 @@ export type AutocompleteDataSource = AutocompleteDataSourceItem[] | string[] | n
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
templateUrl: './nz-autocomplete.component.html',
template: `
<ng-template>
<div
#panel
class="ant-select-dropdown ant-select-dropdown-placement-bottomLeft"
[class.ant-select-dropdown-hidden]="!showPanel"
[ngClass]="nzOverlayClassName"
[ngStyle]="nzOverlayStyle"
[nzNoAnimation]="noAnimation?.nzNoAnimation"
[@slideMotion]="dropDownPosition"
[@.disabled]="noAnimation?.nzNoAnimation"
>
<div style="max-height: 256px; overflow-y: auto; overflow-anchor: none;">
<div style="display: flex; flex-direction: column;">
<ng-template *ngTemplateOutlet="nzDataSource ? optionsTemplate : contentTemplate"></ng-template>
</div>
</div>
</div>
<ng-template #contentTemplate>
<ng-content></ng-content>
</ng-template>
<ng-template #optionsTemplate>
<nz-auto-option *ngFor="let option of nzDataSource" [nzValue]="option">{{ option }}</nz-auto-option>
</ng-template>
</ng-template>
`,
animations: [slideMotion],
styles: [
`
.ant-select-dropdown {
top: 100%;
left: 0;
position: relative;
width: 100%;
margin-top: 4px;
margin-bottom: 4px;
.ant-select-dropdown-hidden {
display: none;
}
`
]
Expand All @@ -70,7 +90,8 @@ export class NzAutocompleteComponent implements AfterContentInit, AfterViewInit,
@Input() @InputBoolean() nzBackfill = false;
@Input() compareWith: CompareWith = (o1, o2) => o1 === o2;
@Input() nzDataSource: AutocompleteDataSource;
@Output() readonly selectionChange: EventEmitter<NzAutocompleteOptionComponent> = new EventEmitter<NzAutocompleteOptionComponent>();
@Output()
readonly selectionChange: EventEmitter<NzAutocompleteOptionComponent> = new EventEmitter<NzAutocompleteOptionComponent>();

showPanel: boolean = true;
isOpen: boolean = false;
Expand All @@ -90,7 +111,8 @@ export class NzAutocompleteComponent implements AfterContentInit, AfterViewInit,
}

/** Provided by content */
@ContentChildren(NzAutocompleteOptionComponent, { descendants: true }) fromContentOptions: QueryList<NzAutocompleteOptionComponent>;
@ContentChildren(NzAutocompleteOptionComponent, { descendants: true })
fromContentOptions: QueryList<NzAutocompleteOptionComponent>;
/** Provided by dataSource */
@ViewChildren(NzAutocompleteOptionComponent) fromDataSourceOptions: QueryList<NzAutocompleteOptionComponent>;

Expand All @@ -101,6 +123,7 @@ export class NzAutocompleteComponent implements AfterContentInit, AfterViewInit,

private activeItemIndex: number = -1;
private selectionChangeSubscription = Subscription.EMPTY;
private optionMouseEnterSubscription = Subscription.EMPTY;
private dataSourceChangeSubscription = Subscription.EMPTY;
/** Options changes listener */
readonly optionSelectionChanges: Observable<NzOptionSelectionChange> = defer(() => {
Expand All @@ -112,6 +135,15 @@ export class NzAutocompleteComponent implements AfterContentInit, AfterViewInit,
switchMap(() => this.optionSelectionChanges)
);
});
readonly optionMouseEnter: Observable<NzAutocompleteOptionComponent> = defer(() => {
if (this.options) {
return merge<NzAutocompleteOptionComponent>(...this.options.map(option => option.mouseEntered));
}
return this.ngZone.onStable.asObservable().pipe(
take(1),
switchMap(() => this.optionMouseEnter)
);
});

constructor(
private changeDetectorRef: ChangeDetectorRef,
Expand All @@ -134,6 +166,7 @@ export class NzAutocompleteComponent implements AfterContentInit, AfterViewInit,
ngOnDestroy(): void {
this.dataSourceChangeSubscription.unsubscribe();
this.selectionChangeSubscription.unsubscribe();
this.optionMouseEnterSubscription.unsubscribe();
}

setVisibility(): void {
Expand Down Expand Up @@ -213,5 +246,13 @@ export class NzAutocompleteComponent implements AfterContentInit, AfterViewInit,
this.clearSelectedOptions(event.source, true);
this.selectionChange.emit(event.source);
});

this.optionMouseEnterSubscription.unsubscribe();
this.optionMouseEnterSubscription = this.optionMouseEnter.subscribe((event: NzAutocompleteOptionComponent) => {
event.setActiveStyles();
this.activeItem = event;
this.activeItemIndex = this.getOptionIndex(this.activeItem.nzValue);
this.clearSelectedOptions(event);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import { FormsModule } from '@angular/forms';

import { NzNoAnimationModule, NzOutletModule } from 'ng-zorro-antd/core';

import { NzAutocompleteOptgroupComponent } from './nz-autocomplete-optgroup.component';
import { NzAutocompleteOptionComponent } from './nz-autocomplete-option.component';
import { NzAutocompleteTriggerDirective } from './nz-autocomplete-trigger.directive';
import { NzAutocompleteComponent } from './nz-autocomplete.component';
import { NzAutocompleteOptgroupComponent } from './autocomplete-optgroup.component';
import { NzAutocompleteOptionComponent } from './autocomplete-option.component';
import { NzAutocompleteTriggerDirective } from './autocomplete-trigger.directive';
import { NzAutocompleteComponent } from './autocomplete.component';

@NgModule({
declarations: [NzAutocompleteComponent, NzAutocompleteOptionComponent, NzAutocompleteTriggerDirective, NzAutocompleteOptgroupComponent],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { Subject } from 'rxjs';

import { createKeyboardEvent, dispatchFakeEvent, dispatchKeyboardEvent, MockNgZone, typeInElement } from 'ng-zorro-antd/core';

import { getNzAutocompleteMissingPanelError } from './autocomplete-trigger.directive';
import { NzAutocompleteComponent, NzAutocompleteModule, NzAutocompleteOptionComponent, NzAutocompleteTriggerDirective } from './index';
import { getNzAutocompleteMissingPanelError } from './nz-autocomplete-trigger.directive';

describe('auto-complete', () => {
let overlayContainer: OverlayContainer;
Expand Down Expand Up @@ -102,11 +102,10 @@ describe('auto-complete', () => {
input.disabled = true;
fixture.detectChanges();

expect(trigger.panelOpen).toBe(false);
dispatchFakeEvent(input, 'focusin');
flush();

fixture.detectChanges();

expect(trigger.panelOpen).toBe(false);
}));

Expand Down Expand Up @@ -243,16 +242,6 @@ describe('auto-complete', () => {
TAB_EVENT = createKeyboardEvent('keydown', TAB);
});

it('should open the panel when the input is focused', () => {
expect(fixture.componentInstance.trigger.panelOpen).toBe(false);

dispatchFakeEvent(input, 'focusin');
fixture.detectChanges();

expect(fixture.componentInstance.trigger.panelOpen).toBe(true);
expect(overlayContainerElement.textContent).toContain('Burns Bay Road');
});

it('should have correct width when setting', () => {
fixture.componentInstance.width = 500;
fixture.detectChanges();
Expand Down Expand Up @@ -603,8 +592,8 @@ describe('auto-complete', () => {
componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);
fixture.detectChanges();

expect(optionEls[0].classList).not.toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[1].classList).toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');
expect(optionEls[1].classList).toContain('ant-select-item-option-active');
});

it('should set the active item to the first option when DOWN key is pressed in last item', () => {
Expand All @@ -616,8 +605,33 @@ describe('auto-complete', () => {
[1, 2, 3].forEach(() => componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT));
fixture.detectChanges();

expect(optionEls[1].classList).not.toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[0].classList).toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[1].classList).not.toContain('ant-select-item-option-active');
expect(optionEls[0].classList).toContain('ant-select-item-option-active');
});

it('should set the active item when mouse is enter', () => {
const componentInstance = fixture.componentInstance;
const optionEls = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;

expect(componentInstance.trigger.panelOpen).toBe(true);

fixture.detectChanges();

dispatchFakeEvent(optionEls[1], 'mouseenter');

fixture.detectChanges();

expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');
expect(optionEls[1].classList).toContain('ant-select-item-option-active');
expect(optionEls[2].classList).not.toContain('ant-select-item-option-active');

dispatchFakeEvent(optionEls[0], 'mouseenter');

fixture.detectChanges();

expect(optionEls[0].classList).toContain('ant-select-item-option-active');
expect(optionEls[1].classList).not.toContain('ant-select-item-option-active');
expect(optionEls[2].classList).not.toContain('ant-select-item-option-active');
});

it('should set the active item to the last option when UP key is pressed', () => {
Expand All @@ -629,9 +643,9 @@ describe('auto-complete', () => {
componentInstance.trigger.handleKeydown(UP_ARROW_EVENT);
fixture.detectChanges();

expect(optionEls[0].classList).not.toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[1].classList).not.toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[2].classList).toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');
expect(optionEls[1].classList).not.toContain('ant-select-item-option-active');
expect(optionEls[2].classList).toContain('ant-select-item-option-active');
});

it('should set the active item to the previous option when UP key is pressed', () => {
Expand All @@ -643,9 +657,9 @@ describe('auto-complete', () => {
[1, 2].forEach(() => componentInstance.trigger.handleKeydown(UP_ARROW_EVENT));
fixture.detectChanges();

expect(optionEls[0].classList).not.toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[1].classList).toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[2].classList).not.toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');
expect(optionEls[1].classList).toContain('ant-select-item-option-active');
expect(optionEls[2].classList).not.toContain('ant-select-item-option-active');
});

it('should set the active item properly after filtering', () => {
Expand All @@ -659,8 +673,8 @@ describe('auto-complete', () => {

const optionEls = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;

expect(optionEls[0].classList).not.toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[1].classList).toContain('ant-select-dropdown-menu-item-active');
expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');
expect(optionEls[1].classList).toContain('ant-select-item-option-active');
expect(optionEls[1].innerText).toEqual('Wall Street');
});

Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 5bec1ff

Please sign in to comment.