Detect click outside Angular component
import { Component, ElementRef, HostListener, Input } from '@angular/core';@Component({ selector: 'selector', template: ` <div> {{text}} </div> `})export class AnotherComponent { public text: String; @HostListener('document:click', ['$event']) clickout(event) { if(this.eRef.nativeElement.contains(event.target)) { this.text = "clicked inside"; } else { this.text = "clicked outside"; } } constructor(private eRef: ElementRef) { this.text = 'no clicks yet'; }}
An alternative to AMagyar's answer. This version works when you click on element that gets removed from the DOM with an ngIf.
http://plnkr.co/edit/4mrn4GjM95uvSbQtxrAS?p=preview
private wasInside = false; @HostListener('click') clickInside() { this.text = "clicked inside"; this.wasInside = true; } @HostListener('document:click') clickout() { if (!this.wasInside) { this.text = "clicked outside"; } this.wasInside = false; }
Binding to document click through @Hostlistener is costly. It can and will have a visible performance impact if you overuse(for example, when building a custom dropdown component and you have multiple instances created in a form).
I suggest adding a @Hostlistener() to the document click event only once inside your main app component. The event should push the value of the clicked target element inside a public subject stored in a global utility service.
@Component({ selector: 'app-root', template: '<router-outlet></router-outlet>'})export class AppComponent { constructor(private utilitiesService: UtilitiesService) {} @HostListener('document:click', ['$event']) documentClick(event: any): void { this.utilitiesService.documentClickedTarget.next(event.target) }}@Injectable({ providedIn: 'root' })export class UtilitiesService { documentClickedTarget: Subject<HTMLElement> = new Subject<HTMLElement>()}
Whoever is interested for the clicked target element should subscribe to the public subject of our utilities service and unsubscribe when the component is destroyed.
export class AnotherComponent implements OnInit { @ViewChild('somePopup', { read: ElementRef, static: false }) somePopup: ElementRef constructor(private utilitiesService: UtilitiesService) { } ngOnInit() { this.utilitiesService.documentClickedTarget .subscribe(target => this.documentClickListener(target)) } documentClickListener(target: any): void { if (this.somePopup.nativeElement.contains(target)) // Clicked inside else // Clicked outside }