diff --git a/src/components/dropdown/nz-dropdown-button.component.ts b/src/components/dropdown/nz-dropdown-button.component.ts index 5181cccf488..7710976de3a 100644 --- a/src/components/dropdown/nz-dropdown-button.component.ts +++ b/src/components/dropdown/nz-dropdown-button.component.ts @@ -74,24 +74,21 @@ export class NzDropDownButtonComponent extends NzDropDownComponent implements On @Output() nzClick = new EventEmitter(); @ViewChild(NzDropDownDirective) _nzOrigin; - ngOnInit() { - debounceTime.call(this._$mouseSubject, 300).subscribe((data: boolean) => { - if (this.nzDisable) { - return; + _onVisibleChange = (visible: boolean) => { + if (this.nzDisable) { + return; + } + if (visible) { + if (!this._triggerWidth) { + this._setTriggerWidth(); } - this.nzVisible = data; - if (this.nzVisible) { - if (!this._triggerWidth) { - this._setTriggerWidth(); - } - } - this.nzVisibleChange.emit(this.nzVisible); - }); - this._nzMenu.setDropDown(true); + } + this.nzVisible = visible; + this._changeDetector.markForCheck(); } /** rewrite afterViewInit hook */ ngAfterViewInit() { - + this._startSubscribe(this.nzVisibleChange.asObservable()); } } diff --git a/src/components/dropdown/nz-dropdown.component.ts b/src/components/dropdown/nz-dropdown.component.ts index 3a3c98525e2..79d1ccb57d1 100644 --- a/src/components/dropdown/nz-dropdown.component.ts +++ b/src/components/dropdown/nz-dropdown.component.ts @@ -7,10 +7,16 @@ import { Renderer2, ContentChild, Output, - EventEmitter, AfterViewInit + EventEmitter, + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef } from '@angular/core'; -import { Subject } from 'rxjs/Subject'; +import { merge } from 'rxjs/observable/merge'; import { debounceTime } from 'rxjs/operator/debounceTime'; +import { Observable } from 'rxjs/Observable'; +import { Subscription } from 'rxjs/Subscription'; +import { Observer } from 'rxjs/Observer' import { NzMenuComponent } from '../menu/nz-menu.component'; import { DropDownAnimation } from '../core/animation/dropdown-animations'; import { NzDropDownDirective } from './nz-dropdown.directive'; @@ -25,6 +31,7 @@ export type NzPlacement = 'bottomLeft' | 'bottomCenter' | 'bottomRight' | 'topLe animations : [ DropDownAnimation ], + changeDetection: ChangeDetectionStrategy.OnPush, template : `
@@ -57,10 +64,10 @@ export type NzPlacement = 'bottomLeft' | 'bottomCenter' | 'bottomRight' | 'topLe export class NzDropDownComponent implements OnInit, OnDestroy, AfterViewInit { _triggerWidth = 0; - _$mouseSubject = new Subject(); _placement: NzPlacement = 'bottomLeft'; _dropDownPosition: 'top' | 'bottom' = 'bottom'; _positions: ConnectionPositionPair[] = [ ...DEFAULT_DROPDOWN_POSITIONS ]; + _subscription: Subscription; @ContentChild(NzDropDownDirective) _nzOrigin; @ContentChild(NzMenuComponent) _nzMenu; @Input() nzTrigger: 'click' | 'hover' = 'hover'; @@ -97,6 +104,14 @@ export class NzDropDownComponent implements OnInit, OnDestroy, AfterViewInit { } } + _hide() { + this.nzVisibleChange.emit(false); + } + + _show() { + this.nzVisibleChange.emit(true); + } + _onPositionChange(position) { this._dropDownPosition = position.connectionPair.originY; } @@ -112,49 +127,67 @@ export class NzDropDownComponent implements OnInit, OnDestroy, AfterViewInit { this._triggerWidth = this._nzOrigin.elementRef.nativeElement.getBoundingClientRect().width; } - _show() { - this._$mouseSubject.next(true); + _onVisibleChange = (visible: boolean) => { + if (visible) { + if (!this._triggerWidth) { + this._setTriggerWidth(); + } + } + this.nzVisible = visible; + this._changeDetector.markForCheck(); } - _hide() { - this._$mouseSubject.next(false); + _startSubscribe(observable$: Observable) { + this._subscription = observable$ + .subscribe(this._onVisibleChange) } ngOnInit() { - debounceTime.call(this._$mouseSubject, 300).subscribe((data: boolean) => { - this.nzVisible = data; - if (this.nzVisible) { - if (!this._triggerWidth) { - this._setTriggerWidth(); - } - } - this.nzVisibleChange.emit(this.nzVisible); - }); this._nzMenu.setDropDown(true); } ngOnDestroy() { - this._$mouseSubject.unsubscribe(); + this._subscription.unsubscribe(); } - ngAfterViewInit() { + let mouse$: Observable if (this.nzTrigger === 'hover') { - this._renderer.listen(this._nzOrigin.elementRef.nativeElement, 'mouseenter', () => this._show()); - this._renderer.listen(this._nzOrigin.elementRef.nativeElement, 'mouseleave', () => this._hide()); + mouse$ = Observable.create((observer: Observer) => { + const disposeMouseEnter = this._renderer.listen(this._nzOrigin.elementRef.nativeElement, 'mouseenter', () => { + observer.next(true); + }); + const disposeMouseLeave = this._renderer.listen(this._nzOrigin.elementRef.nativeElement, 'mouseleave', () => { + observer.next(false); + }); + return () => { + disposeMouseEnter(); + disposeMouseLeave(); + } + }); } if (this.nzTrigger === 'click') { - this._renderer.listen(this._nzOrigin.elementRef.nativeElement, 'click', (e) => { - e.preventDefault(); - this._show() + mouse$ = Observable.create((observer: Observer) => { + const dispose = this._renderer.listen(this._nzOrigin.elementRef.nativeElement, 'click', (e) => { + e.preventDefault(); + observer.next(true); + }); + return () => dispose(); }); } + const observable$ = debounceTime.call( + merge( + mouse$, + this.nzVisibleChange.asObservable() + ) + , 300); + this._startSubscribe(observable$); } get _hasBackdrop() { return this.nzTrigger === 'click'; } - constructor(private _renderer: Renderer2) { + constructor(private _renderer: Renderer2, protected _changeDetector: ChangeDetectorRef) { } }