Skip to content

Commit

Permalink
fix(module:upload): do not trigger change detection for `nz-upload-bt…
Browse files Browse the repository at this point in the history
…n` (#7032)
  • Loading branch information
arturovt authored Nov 4, 2021
1 parent b18c050 commit 47f91c7
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 10 deletions.
37 changes: 29 additions & 8 deletions components/upload/upload-btn.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@

import { ENTER } from '@angular/cdk/keycodes';
import { HttpClient, HttpEvent, HttpEventType, HttpHeaders, HttpRequest, HttpResponse } from '@angular/common/http';
import { Component, ElementRef, Input, OnDestroy, Optional, ViewChild, ViewEncapsulation } from '@angular/core';
import { Observable, of, Subscription } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import {
Component,
ElementRef,
Input,
NgZone,
OnInit,
OnDestroy,
Optional,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { fromEvent, Observable, of, Subject, Subscription } from 'rxjs';
import { map, switchMap, takeUntil } from 'rxjs/operators';

import { warn } from 'ng-zorro-antd/core/logger';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
Expand All @@ -22,24 +32,24 @@ import { NzUploadFile, NzUploadXHRArgs, ZipButtonOptions } from './interface';
'[attr.tabindex]': '"0"',
'[attr.role]': '"button"',
'[class.ant-upload-disabled]': 'options.disabled',
'(click)': 'onClick()',
'(keydown)': 'onKeyDown($event)',
'(drop)': 'onFileDrop($event)',
'(dragover)': 'onFileDrop($event)'
},
preserveWhitespaces: false,
encapsulation: ViewEncapsulation.None
})
export class NzUploadBtnComponent implements OnDestroy {
export class NzUploadBtnComponent implements OnInit, OnDestroy {
reqs: { [key: string]: Subscription } = {};
private destroy = false;
@ViewChild('file', { static: false }) file!: ElementRef;
private destroy$ = new Subject<void>();
@ViewChild('file', { static: true }) file!: ElementRef<HTMLInputElement>;
@Input() options!: ZipButtonOptions;
onClick(): void {
if (this.options.disabled || !this.options.openFileDialogOnClick) {
return;
}
(this.file.nativeElement as HTMLInputElement).click();
this.file.nativeElement.click();
}

onKeyDown(e: KeyboardEvent): void {
Expand Down Expand Up @@ -339,7 +349,7 @@ export class NzUploadBtnComponent implements OnDestroy {
}
}

constructor(@Optional() private http: HttpClient, private elementRef: ElementRef) {
constructor(private ngZone: NgZone, @Optional() private http: HttpClient, private elementRef: ElementRef) {
// TODO: move to host after View Engine deprecation
this.elementRef.nativeElement.classList.add('ant-upload');

Expand All @@ -348,8 +358,19 @@ export class NzUploadBtnComponent implements OnDestroy {
}
}

ngOnInit(): void {
// Caretaker note: `input[type=file].click()` will open a native OS file picker,
// it doesn't require Angular to run `ApplicationRef.tick()`.
this.ngZone.runOutsideAngular(() => {
fromEvent(this.elementRef.nativeElement, 'click')
.pipe(takeUntil(this.destroy$))
.subscribe(() => this.onClick());
});
}

ngOnDestroy(): void {
this.destroy = true;
this.destroy$.next();
this.abort();
}
}
25 changes: 23 additions & 2 deletions components/upload/upload.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { CommonModule } from '@angular/common';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { Component, DebugElement, Injector, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
import {
ApplicationRef,
Component,
DebugElement,
Injector,
TemplateRef,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
Expand Down Expand Up @@ -998,7 +1006,20 @@ describe('upload', () => {
fixture.detectChanges();
});

describe('should be trigger upload', () => {
describe('should trigger upload', () => {
describe('change detection', () => {
it('should not run change detection when the <input type=file> is being clicked', () => {
const appRef = TestBed.inject(ApplicationRef);
spyOn(appRef, 'tick');
spyOn(instance.comp.file.nativeElement, 'click');
expect(instance.comp.file.nativeElement.click).not.toHaveBeenCalled();
fixture.debugElement.query(By.css('div')).nativeElement.click();
// Caretaker note: previously click events on the `nz-upload-btn` elements did trigger
// change detection since they were added via the `host` property.
expect(appRef.tick).toHaveBeenCalledTimes(0);
expect(instance.comp.file.nativeElement.click).toHaveBeenCalled();
});
});
describe('via onClick', () => {
it('', () => {
spyOn(instance.comp.file.nativeElement, 'click');
Expand Down

0 comments on commit 47f91c7

Please sign in to comment.