Skip to content

Instantly share code, notes, and snippets.

@varnastadeus
Last active August 24, 2018 02:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save varnastadeus/57006117a61f1877b2dc2d18a93fa011 to your computer and use it in GitHub Desktop.
Save varnastadeus/57006117a61f1877b2dc2d18a93fa011 to your computer and use it in GitHub Desktop.
import {
ComponentRef,
Directive,
ElementRef,
Input,
OnDestroy,
OnInit
} from '@angular/core';
import { filter, takeUntil } from 'rxjs/operators';
import { fromEvent } from 'rxjs/observable/fromEvent';
import { merge } from 'rxjs/observable/merge';
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
import { NgbPopoverWindow } from '@ng-bootstrap/ng-bootstrap/popover/popover';
import { Subject } from 'rxjs/Subject';
@Directive({
selector: '[handlePopoverClose][ngbPopover]'
})
export class HandlePopoverCloseDirective implements OnInit, OnDestroy {
@Input('handlePopoverClose') closeOnPopoverBodyClick = false;
private destroy$ = new Subject<void>();
constructor(
private elementRef: ElementRef,
private ngbPopover: NgbPopover) {
}
ngOnInit() {
const closedOrDestroyed$ = merge(this.ngbPopover.hidden, this.destroy$);
const events$ = merge(
fromEvent(document, 'click'),
fromEvent(document, 'keydown').pipe(filter((event: KeyboardEvent) => event.keyCode === 27)) // esc
);
this.ngbPopover.shown.subscribe(() => {
events$
.pipe(takeUntil(closedOrDestroyed$))
.subscribe((event: MouseEvent) => this.handleCloseEvents(event));
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
private handleCloseEvents(event: MouseEvent): void {
if (event.type === 'keydown') {
this.ngbPopover.close();
return;
}
const target = event.target as Element;
if (!this.elementRef.nativeElement.contains(target)) {
const popoverWindowRef: ComponentRef<NgbPopoverWindow> = (this.ngbPopover as any)._windowRef;
if (!popoverWindowRef.location.nativeElement.contains(event.target) || this.closeOnPopoverBodyClick) {
this.ngbPopover.close();
}
}
}
}
@envynoiz
Copy link

If you wanna use this directive and you're using RxJs 6, it's necessary to update the syntax for importing the packages like that:

import { Subject, fromEvent, merge } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment