Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(module:cascader): do not run change detection on change event #7312

Merged
merged 1 commit into from Apr 21, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 35 additions & 10 deletions components/cascader/cascader.component.ts
Expand Up @@ -29,13 +29,14 @@ import {
ViewEncapsulation
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { fromEvent, Subject } from 'rxjs';
import { startWith, takeUntil } from 'rxjs/operators';
import { BehaviorSubject, EMPTY, fromEvent, Observable } from 'rxjs';
import { startWith, switchMap, takeUntil } from 'rxjs/operators';

import { slideMotion } from 'ng-zorro-antd/core/animation';
import { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';
import { NzNoAnimationDirective } from 'ng-zorro-antd/core/no-animation';
import { DEFAULT_CASCADER_POSITIONS } from 'ng-zorro-antd/core/overlay';
import { NzDestroyService } from 'ng-zorro-antd/core/services';
import { BooleanInput, NgClassType, NgStyleInterface, NzSafeAny } from 'ng-zorro-antd/core/types';
import { InputBoolean, toArray } from 'ng-zorro-antd/core/util';
import { NzCascaderI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';
Expand Down Expand Up @@ -79,7 +80,6 @@ const defaultDisplayRender = (labels: string[]): string => labels.join(' / ');
[(ngModel)]="inputValue"
(blur)="handleInputBlur()"
(focus)="handleInputFocus()"
(change)="$event.stopPropagation()"
/>
</span>
<span *ngIf="showLabelRender" class="ant-select-selection-item" [title]="labelRenderText">
Expand Down Expand Up @@ -192,7 +192,8 @@ const defaultDisplayRender = (labels: string[]): string => labels.join(' / ');
useExisting: forwardRef(() => NzCascaderComponent),
multi: true
},
NzCascaderService
NzCascaderService,
NzDestroyService
],
host: {
'[attr.tabIndex]': '"0"',
Expand All @@ -218,7 +219,17 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
static ngAcceptInputType_nzDisabled: BooleanInput;

@ViewChild('selectContainer', { static: false }) selectContainer!: ElementRef;
@ViewChild('input', { static: false }) input!: ElementRef;

@ViewChild('input', { static: false })
set input(input: ElementRef<HTMLInputElement> | undefined) {
this.input$.next(input);
}
get input(): ElementRef<HTMLInputElement> | undefined {
return this.input$.getValue();
}
/** Used to store the native `<input type="search" />` element since it might be set asynchronously. */
private input$ = new BehaviorSubject<ElementRef<HTMLInputElement> | undefined>(undefined);

@ViewChild('menu', { static: false }) menu!: ElementRef;
@ViewChild(CdkConnectedOverlay, { static: false }) overlay!: CdkConnectedOverlay;
@ViewChildren(NzCascaderOptionComponent) cascaderItems!: QueryList<NzCascaderOptionComponent>;
Expand Down Expand Up @@ -290,7 +301,6 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
locale!: NzCascaderI18nInterface;
dir: Direction = 'ltr';

private destroy$ = new Subject<void>();
private inputString = '';
private isOpening = false;
private delayMenuTimer: number | null = null;
Expand Down Expand Up @@ -347,6 +357,7 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
private ngZone: NgZone,
private cdr: ChangeDetectorRef,
private i18nService: NzI18nService,
private destroy$: NzDestroyService,
elementRef: ElementRef,
renderer: Renderer2,
@Optional() private directionality: Directionality,
Expand Down Expand Up @@ -415,12 +426,11 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
srv.$redraw.next();
});

this.setupChangeListener();
this.setupKeydownListener();
}

ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
this.clearDelayMenuTimer();
this.clearDelaySelectTimer();
}
Expand Down Expand Up @@ -504,14 +514,14 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,

focus(): void {
if (!this.isFocused) {
(this.input ? this.input.nativeElement : this.el).focus();
(this.input?.nativeElement || this.el).focus();
this.isFocused = true;
}
}

blur(): void {
if (this.isFocused) {
(this.input ? this.input.nativeElement : this.el).blur();
(this.input?.nativeElement || this.el).blur();
this.isFocused = false;
}
}
Expand Down Expand Up @@ -770,6 +780,21 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
});
}

private setupChangeListener(): void {
this.input$
.pipe(
switchMap(input =>
input
? new Observable<Event>(subscriber =>
this.ngZone.runOutsideAngular(() => fromEvent(input.nativeElement, 'change').subscribe(subscriber))
)
: EMPTY
),
takeUntil(this.destroy$)
)
.subscribe(event => event.stopPropagation());
}

private setupKeydownListener(): void {
this.ngZone.runOutsideAngular(() => {
fromEvent<KeyboardEvent>(this.el, 'keydown')
Expand Down