An obvious right answer would be to use a service and have your popup inject this service and register to it when they open and close, to know if there is a current popup open.
But lets look at another, less obvious solution.. Which can be frowned upon, but for tiny things like this, really seems to be the easiest and readable way. To use a static property on your Popover
class:
@Directive({ selector: '[popover]'})
class Popover {
private static currentPopover: Popover;
private get active() {
return this === Popover.currentPopover;
}
private component: ComponentRef<any>;
constructor(
private vcRef: ViewContainerRef,
private cfResolver: ComponentFactoryResolver,
private elementRef: ElementRef
) {}
@HostListener('document:click')
onDocClick() {
if (this.active) {
this.close();
}
}
@HostListener('click', ['$event'])
toggle(event: MouseEvent) {
if (Popover.currentPopover && !this.active) {
Popover.currentPopover.close();
}
if (!this.active) {
this.open();
event.stopImmediatePropagation();
}
}
open() {
const componentFactory = this.cfResolver.resolveComponentFactory(PopoverWindow);
this.component = this.vcRef.createComponent(componentFactory);
Popover.currentPopover = this;
}
close() {
this.vcRef.clear()
this.component.destroy();
this.component = null;
Popover.currentPopover = undefined;
}
}
I've also added a document click listener, so when you click anywhere else, it closes the current popup.
plunkr
But if you are willing to use a service (untested code):
export class PopoverService {
private activePopover: Popover;
public setActive(popover: Popover): void {
if (this.activePopover) {
this.activePopover.close();
}
this.activePopover = popover;
}
public isActive(popover: Popover): boolean {
return popover === this.activePopover;
}
}
And your directive will look like this:
@Directive({ selector: '[popover]'})
class Popover {
private get active() {
return this.popoverService.isActive(this);
}
private component: ComponentRef<any>;
constructor(
private vcRef: ViewContainerRef,
private cfResolver: ComponentFactoryResolver,
private elementRef: ElementRef,
private popoverService: PopoverService
) {}
@HostListener('document:click')
onDocClick() {
if (this.active) {
this.close();
}
}
@HostListener('click', ['$event'])
toggle(event: MouseEvent) {
if (!this.active) {
this.open();
event.stopImmediatePropagation();
}
}
open() {
const componentFactory = this.cfResolver.resolveComponentFactory(PopoverWindow);
this.component = this.vcRef.createComponent(componentFactory);
this.popoverService.setActive(this);
}
close() {
this.vcRef.clear()
this.component.destroy();
this.component = null;
}
}