From 222425ae51cdbcb8756f63a8f2177d9d500ecc67 Mon Sep 17 00:00:00 2001 From: isoden Date: Sat, 6 Jan 2018 05:28:03 +0900 Subject: [PATCH 1/4] use Renderer2 #22 --- src/click-outside.directive.ts | 42 +++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/click-outside.directive.ts b/src/click-outside.directive.ts index 568182c..6c2aca0 100644 --- a/src/click-outside.directive.ts +++ b/src/click-outside.directive.ts @@ -12,8 +12,13 @@ import { PLATFORM_ID, SimpleChanges, NgZone, + Renderer2, } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; +import { merge } from 'rxjs/observable/merge'; +import { takeUntil } from 'rxjs/operators/takeUntil'; @Injectable() @Directive({ selector: '[clickOutside]' }) @@ -31,7 +36,12 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { private _nodesExcluded: Array = []; private _events: Array = ['click']; + private _beforeInit: Subject = new Subject(); + private _onDestroy: Subject = new Subject(); + private _onOutsideClick: Subject = new Subject(); + constructor(private _el: ElementRef, + private _renderer2: Renderer2, private _ngZone: NgZone, @Inject(PLATFORM_ID) private platformId: Object) { this._initOnClickBody = this._initOnClickBody.bind(this); @@ -47,11 +57,11 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { ngOnDestroy() { if (!isPlatformBrowser(this.platformId)) { return; } - if (this.attachOutsideOnClick) { - this._events.forEach(e => this._el.nativeElement.removeEventListener(e, this._initOnClickBody)); - } + this._onDestroy.next(); + this._onDestroy.complete(); - this._events.forEach(e => document.body.removeEventListener(e, this._onClickBody)); + this._onOutsideClick.complete(); + this._beforeInit.complete(); } ngOnChanges(changes: SimpleChanges) { @@ -63,6 +73,8 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { } private _init() { + this._beforeInit.next(); + if (this.clickOutsideEvents !== '') { this._events = this.clickOutsideEvents.split(',').map(e => e.trim()); } @@ -71,7 +83,8 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { if (this.attachOutsideOnClick) { this._ngZone.runOutsideAngular(() => { - this._events.forEach(e => this._el.nativeElement.addEventListener(e, this._initOnClickBody)); + this._listenAll(this._el.nativeElement, ...this._events) + .subscribe(this._initOnClickBody); }); } else { this._initOnClickBody(); @@ -88,7 +101,11 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { private _initClickListeners() { this._ngZone.runOutsideAngular(() => { - this._events.forEach(e => document.body.addEventListener(e, this._onClickBody)); + this._listenAll('body', ...this._events) + .pipe( + takeUntil(this._onOutsideClick), + ) + .subscribe(this._onClickBody); }); } @@ -118,7 +135,7 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { this._ngZone.run(() => this.clickOutside.emit(ev)); if (this.attachOutsideOnClick) { - this._events.forEach(e => document.body.removeEventListener(e, this._onClickBody)); + this._onOutsideClick.next(); } } } @@ -130,6 +147,15 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { } } - return false; + private _listenAll(target: 'window' | 'document' | 'body' | any, ...eventNames: string[]): Observable { + const sources = eventNames.map(eventName => { + return new Observable(observer => this._renderer2.listen(target, eventName, ev => observer.next(ev))); + }); + + return merge(...sources) + .pipe( + takeUntil(this._beforeInit), + takeUntil(this._onDestroy), + ); } } From a7cfd1017af25696e3d8361e10551f85b772be22 Mon Sep 17 00:00:00 2001 From: isoden Date: Sat, 6 Jan 2018 05:39:15 +0900 Subject: [PATCH 2/4] make clickOutsideEvents a setter --- src/click-outside.directive.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/click-outside.directive.ts b/src/click-outside.directive.ts index 6c2aca0..7ffb68e 100644 --- a/src/click-outside.directive.ts +++ b/src/click-outside.directive.ts @@ -28,7 +28,9 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { @Input() delayClickOutsideInit: boolean = false; @Input() exclude: string = ''; @Input() excludeBeforeClick: boolean = false; - @Input() clickOutsideEvents: string = ''; + @Input() set clickOutsideEvents(events: string) { + this._events = events.split(',').map(e => e.trim()); + } @Input() clickOutsideEnabled: boolean = true; @Output() clickOutside: EventEmitter = new EventEmitter(); @@ -75,10 +77,6 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { private _init() { this._beforeInit.next(); - if (this.clickOutsideEvents !== '') { - this._events = this.clickOutsideEvents.split(',').map(e => e.trim()); - } - this._excludeCheck(); if (this.attachOutsideOnClick) { From 19d1043d506afd534e60ece28de3c26370afe88e Mon Sep 17 00:00:00 2001 From: isoden Date: Sat, 6 Jan 2018 05:41:49 +0900 Subject: [PATCH 3/4] use cached value --- src/click-outside.directive.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/click-outside.directive.ts b/src/click-outside.directive.ts index 7ffb68e..ab4859c 100644 --- a/src/click-outside.directive.ts +++ b/src/click-outside.directive.ts @@ -37,6 +37,7 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { private _nodesExcluded: Array = []; private _events: Array = ['click']; + private _isPlatformBrowser: boolean = isPlatformBrowser(this.platformId); private _beforeInit: Subject = new Subject(); private _onDestroy: Subject = new Subject(); @@ -51,13 +52,13 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { } ngOnInit() { - if (!isPlatformBrowser(this.platformId)) { return; } + if (!this._isPlatformBrowser) { return; } this._init(); } ngOnDestroy() { - if (!isPlatformBrowser(this.platformId)) { return; } + if (!this._isPlatformBrowser) { return; } this._onDestroy.next(); this._onDestroy.complete(); @@ -67,7 +68,7 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { } ngOnChanges(changes: SimpleChanges) { - if (!isPlatformBrowser(this.platformId)) { return; } + if (!this._isPlatformBrowser) { return; } if (changes['attachOutsideOnClick'] || changes['exclude']) { this._init(); From 4c96cd639c5d5fb0d67e351da290d80a91ffab4b Mon Sep 17 00:00:00 2001 From: isoden Date: Sat, 6 Jan 2018 05:42:11 +0900 Subject: [PATCH 4/4] simplify --- src/click-outside.directive.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/click-outside.directive.ts b/src/click-outside.directive.ts index ab4859c..e4bb4c4 100644 --- a/src/click-outside.directive.ts +++ b/src/click-outside.directive.ts @@ -140,11 +140,8 @@ export class ClickOutsideDirective implements OnInit, OnChanges, OnDestroy { } private _shouldExclude(target): boolean { - for (let excludedNode of this._nodesExcluded) { - if (excludedNode.contains(target)) { - return true; - } - } + return this._nodesExcluded.some(excludedNode => excludedNode.contains(target)); + } private _listenAll(target: 'window' | 'document' | 'body' | any, ...eventNames: string[]): Observable { const sources = eventNames.map(eventName => {