diff --git a/components/input-number/input-number.component.ts b/components/input-number/input-number.component.ts
index 8c8af32fe2..0545763fed 100644
--- a/components/input-number/input-number.component.ts
+++ b/components/input-number/input-number.component.ts
@@ -26,9 +26,10 @@ import {
ViewEncapsulation
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
-import { fromEvent, Subject } from 'rxjs';
+import { fromEvent, merge } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
+import { NzDestroyService } from 'ng-zorro-antd/core/services';
import { BooleanInput, NzSizeLDSType, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';
import { InputBoolean, isNotNil } from 'ng-zorro-antd/core/util';
@@ -38,21 +39,19 @@ import { InputBoolean, isNotNil } from 'ng-zorro-antd/core/util';
template: `
@@ -82,7 +81,8 @@ import { InputBoolean, isNotNil } from 'ng-zorro-antd/core/util';
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NzInputNumberComponent),
multi: true
- }
+ },
+ NzDestroyService
],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
@@ -104,7 +104,6 @@ export class NzInputNumberComponent implements ControlValueAccessor, AfterViewIn
private autoStepTimer?: number;
private parsedValue?: string | number;
private value?: number;
- private destroy$ = new Subject();
displayValue?: string | number;
isFocused = false;
disabledUp = false;
@@ -114,6 +113,11 @@ export class NzInputNumberComponent implements ControlValueAccessor, AfterViewIn
onTouched: OnTouchedType = () => {};
@Output() readonly nzBlur = new EventEmitter();
@Output() readonly nzFocus = new EventEmitter();
+ /** The native `` element. */
+ @ViewChild('upHandler', { static: true }) upHandler!: ElementRef;
+ /** The native `` element. */
+ @ViewChild('downHandler', { static: true }) downHandler!: ElementRef;
+ /** The native `` element. */
@ViewChild('inputElement', { static: true }) inputElement!: ElementRef;
@Input() nzSize: NzSizeLDSType = 'default';
@Input() nzMin: number = -Infinity;
@@ -372,30 +376,30 @@ export class NzInputNumberComponent implements ControlValueAccessor, AfterViewIn
private elementRef: ElementRef,
private cdr: ChangeDetectorRef,
private focusMonitor: FocusMonitor,
- @Optional() private directionality: Directionality
+ @Optional() private directionality: Directionality,
+ private destroy$: NzDestroyService
) {}
ngOnInit(): void {
- this.focusMonitor
- .monitor(this.elementRef, true)
- .pipe(takeUntil(this.destroy$))
- .subscribe(focusOrigin => {
- if (!focusOrigin) {
- this.isFocused = false;
- this.updateDisplayValue(this.value!);
- this.nzBlur.emit();
- Promise.resolve().then(() => this.onTouched());
- } else {
- this.isFocused = true;
- this.nzFocus.emit();
- }
- });
+ this.focusMonitor.monitor(this.elementRef, true).subscribe(focusOrigin => {
+ if (!focusOrigin) {
+ this.isFocused = false;
+ this.updateDisplayValue(this.value!);
+ this.nzBlur.emit();
+ Promise.resolve().then(() => this.onTouched());
+ } else {
+ this.isFocused = true;
+ this.nzFocus.emit();
+ }
+ });
this.dir = this.directionality.value;
this.directionality.change.pipe(takeUntil(this.destroy$)).subscribe((direction: Direction) => {
this.dir = direction;
});
+ this.setupHandlersListeners();
+
this.ngZone.runOutsideAngular(() => {
fromEvent(this.inputElement.nativeElement, 'keyup')
.pipe(takeUntil(this.destroy$))
@@ -445,7 +449,18 @@ export class NzInputNumberComponent implements ControlValueAccessor, AfterViewIn
ngOnDestroy(): void {
this.focusMonitor.stopMonitoring(this.elementRef);
- this.destroy$.next();
- this.destroy$.complete();
+ }
+
+ private setupHandlersListeners(): void {
+ this.ngZone.runOutsideAngular(() => {
+ merge(
+ fromEvent(this.upHandler.nativeElement, 'mouseup'),
+ fromEvent(this.upHandler.nativeElement, 'mouseleave'),
+ fromEvent(this.downHandler.nativeElement, 'mouseup'),
+ fromEvent(this.downHandler.nativeElement, 'mouseleave')
+ )
+ .pipe(takeUntil(this.destroy$))
+ .subscribe(() => this.stop());
+ });
}
}
diff --git a/components/input-number/input-number.spec.ts b/components/input-number/input-number.spec.ts
index 711356c936..8528dce164 100644
--- a/components/input-number/input-number.spec.ts
+++ b/components/input-number/input-number.spec.ts
@@ -5,7 +5,7 @@ import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule } from '@angul
import { By } from '@angular/platform-browser';
import { take } from 'rxjs/operators';
-import { createKeyboardEvent, dispatchEvent, dispatchFakeEvent } from 'ng-zorro-antd/core/testing';
+import { createKeyboardEvent, createMouseEvent, dispatchEvent, dispatchFakeEvent } from 'ng-zorro-antd/core/testing';
import { NzInputNumberComponent } from './input-number.component';
import { NzInputNumberModule } from './input-number.module';
@@ -429,6 +429,24 @@ describe('input number', () => {
done();
});
});
+ it('should not run change detection when `mouseup` and `mouseleave` events are dispatched on handlers', () => {
+ const appRef = TestBed.inject(ApplicationRef);
+ spyOn(appRef, 'tick');
+ spyOn(inputNumber.componentInstance, 'stop').and.callThrough();
+
+ const mouseupEvent = createMouseEvent('mouseup');
+ const mouseleaveEvent = createMouseEvent('mouseleave');
+
+ upHandler.dispatchEvent(mouseupEvent);
+ upHandler.dispatchEvent(mouseleaveEvent);
+
+ downHandler.dispatchEvent(mouseupEvent);
+ downHandler.dispatchEvent(mouseleaveEvent);
+
+ expect(appRef.tick).not.toHaveBeenCalled();
+ // We have dispatched 4 events that are followed by calling `stop()`.
+ expect(inputNumber.componentInstance.stop).toHaveBeenCalledTimes(4);
+ });
});
});