Skip to content

Commit

Permalink
perf(module:select): do not run change detection unnecessarily on cli…
Browse files Browse the repository at this point in the history
…ck events (#7175)
  • Loading branch information
arturovt committed Feb 18, 2022
1 parent 7d091bb commit fd63d22
Showing 1 changed file with 32 additions and 22 deletions.
54 changes: 32 additions & 22 deletions components/select/select.component.ts
Expand Up @@ -19,6 +19,7 @@ import {
forwardRef,
Host,
Input,
NgZone,
OnChanges,
OnDestroy,
OnInit,
Expand All @@ -31,7 +32,7 @@ import {
ViewEncapsulation
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { BehaviorSubject, combineLatest, merge } from 'rxjs';
import { BehaviorSubject, combineLatest, fromEvent, merge } from 'rxjs';
import { startWith, switchMap, takeUntil } from 'rxjs/operators';

import { slideMotion } from 'ng-zorro-antd/core/animation';
Expand Down Expand Up @@ -119,7 +120,6 @@ 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)"
Expand Down Expand Up @@ -161,8 +161,7 @@ export type NzSelectSizeType = 'large' | 'default' | 'small';
'[class.ant-select-focused]': 'nzOpen || focused',
'[class.ant-select-single]': `nzMode === 'default'`,
'[class.ant-select-multiple]': `nzMode !== 'default'`,
'[class.ant-select-rtl]': `dir === 'rtl'`,
'(click)': 'onHostClick()'
'[class.ant-select-rtl]': `dir === 'rtl'`
}
})
export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterContentInit, OnChanges, OnDestroy {
Expand Down Expand Up @@ -292,14 +291,6 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
this.clearInput();
}

onHostClick(): void {
if ((this.nzOpen && this.nzShowSearch) || this.nzDisabled) {
return;
}

this.setOpenState(!this.nzOpen);
}

updateListOfContainerItem(): void {
let listOfContainerItem = this.listOfTagAndTemplateItem
.filter(item => !item.nzHide)
Expand Down Expand Up @@ -384,12 +375,6 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
this.clearInput();
}

onOverlayKeyDown(e: KeyboardEvent): void {
if (e.keyCode === ESCAPE) {
this.setOpenState(false);
}
}

onKeyDown(e: KeyboardEvent): void {
if (this.nzDisabled) {
return;
Expand Down Expand Up @@ -474,7 +459,7 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
}

onClickOutside(event: MouseEvent): void {
if (!this.elementRef.nativeElement.contains(event.target)) {
if (!this.host.nativeElement.contains(event.target as HTMLElement)) {
this.setOpenState(false);
}
}
Expand Down Expand Up @@ -516,10 +501,11 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
}

constructor(
private ngZone: NgZone,
private destroy$: NzDestroyService,
public nzConfigService: NzConfigService,
private cdr: ChangeDetectorRef,
private elementRef: ElementRef,
private host: ElementRef<HTMLElement>,
private platform: Platform,
private focusMonitor: FocusMonitor,
@Optional() private directionality: Directionality,
Expand Down Expand Up @@ -592,7 +578,7 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon

ngOnInit(): void {
this.focusMonitor
.monitor(this.elementRef, true)
.monitor(this.host, true)
.pipe(takeUntil(this.destroy$))
.subscribe(focusOrigin => {
if (!focusOrigin) {
Expand Down Expand Up @@ -640,6 +626,29 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
});

this.dir = this.directionality.value;

this.ngZone.runOutsideAngular(() =>
fromEvent(this.host.nativeElement, 'click')
.pipe(takeUntil(this.destroy$))
.subscribe(() => {
if ((this.nzOpen && this.nzShowSearch) || this.nzDisabled) {
return;
}

this.ngZone.run(() => this.setOpenState(!this.nzOpen));
})
);

// Caretaker note: we could've added this listener within the template `(overlayKeydown)="..."`,
// but with this approach, it'll run change detection on each keyboard click, and also it'll run
// `markForCheck()` internally, which means the whole component tree (starting from the root and
// going down to the select component) will be re-checked and updated (if needed).
// This is safe to do that manually since `setOpenState()` calls `markForCheck()` if needed.
this.cdkConnectedOverlay.overlayKeydown.pipe(takeUntil(this.destroy$)).subscribe(event => {
if (event.keyCode === ESCAPE) {
this.setOpenState(false);
}
});
}

ngAfterContentInit(): void {
Expand Down Expand Up @@ -679,8 +688,9 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
});
}
}

ngOnDestroy(): void {
cancelRequestAnimationFrame(this.requestId);
this.focusMonitor.stopMonitoring(this.elementRef);
this.focusMonitor.stopMonitoring(this.host);
}
}

0 comments on commit fd63d22

Please sign in to comment.