我有一个'CloseHandlerDirective',可以在事件目标之外的任何地方点击或按下escape时处理模态和下拉的关闭。
import { Directive, ElementRef, AfterContentInit, Output, EventEmitter, Renderer } from '@angular/core';
@Directive({
selector: '[closeHandler]'
})
export class CloseHandlerDirective implements AfterContentInit {
@Output() closeHandler: EventEmitter<Event> = new EventEmitter();
private _visible: boolean = false;
private _globalClickUnregister: Function;
private _globalKeyDownUnregister: Function;
private _elementClickUnregister: Function;
constructor(private _elementRef: ElementRef, private renderer: Renderer) {
this._render = this._render.bind(this);
}
ngAfterContentInit(): void {
this._elementClickUnregister = this.renderer.listen(this._elementRef.nativeElement, 'click', this._render);
}
_render(event: Event): void {
event.stopPropagation();
this._visible = !this._visible;
if (this._visible) {
// Emits a close event, if it detects a click outside of the native Element
this._globalClickUnregister = this.renderer
.listenGlobal('document', 'click', (clickEvent: Event) => {
const CLICKED_INSIDE: Boolean = this._elementRef.nativeElement.parentElement
.contains(clickEvent.target);
if (!CLICKED_INSIDE) {
this.closeHandler.emit(null);
this._visible = false;
this._globalClickUnregister();
if(this._globalKeyDownUnregister) {
this._globalKeyDownUnregister();
}
}
});
// Emits a close event, if it detects that "Escape" was pressed
this._globalKeyDownUnregister = this.renderer
.listenGlobal('document', 'keydown', (keyDownEvent: KeyboardEvent) => {
let key: String = keyDownEvent.key;
if (key === 'Escape' || key === 'Esc') {
this.closeHandler.emit(null);
this._visible = false;
this._globalKeyDownUnregister();
if(this._globalClickUnregister) {
this._globalClickUnregister();
}
}
});
} else {
if (this._globalClickUnregister) {
this._globalClickUnregister();
}
if(this._globalKeyDownUnregister) {
this._globalKeyDownUnregister();
}
}
}
}
除了一件事以外,它的工作非常好:
我有一个在表格行内的下拉列表。整个表行上有一个routerLink。我在EventListener中首先使用event.stopPropagation();
,因此事件不会冒泡到routerLink。否则下拉列表将不会显示,它将直接进入路由器指向的页面。
但这也意味着当我每页有多个下拉列表并打开第一个下拉列表并打开另一个下拉列表时,第一个下拉列表不会关闭,因为它没有注册为“外部点击”,因为{{ 1}}。
如何解决此问题,以便一次只允许我的下拉组件的一个实例打开?