How to detect click outside of an element in Angular?
Here is the link to the working demo: Stackblitz Demo
I would do this by using the Angular recommended approach which is also easy to develop apps in environments with no DOM access, I mean Renderer 2
class which is an abstraction provided by Angular in the form of a service that allows manipulating elements of your app without having to touch the DOM directly.
In this approach, you need to inject Renderer2
into your component constructor, which the Renderer2
lets us to listen
to triggered events elegantly. It just takes the element you're going to listen on as the first argument which can be window
, document
, body
or any other element reference. For the second argument it takes the event we're going to listen on which in this case is click
, and the third argument is actually the callback function which we do it by arrow function.
this.renderer.listen('window', 'click',(e:Event)=>{ // your code here})
The rest of the solution is easy, you just need to set a boolean flag which keeps the status of the menu (or panel) visibility, and what we should do is to assign false
to that flag when it's clicked outside of the menu.
HTML
<button #toggleButton (click)="toggleMenu()"> Toggle Menu</button>
<div class="menu" *ngIf="isMenuOpen" #menu>
I'm the menu. Click outside to close me
</div>
app.component.ts
export class AppComponent {
/**
* This is the toogle button elemenbt, look at HTML and see its defination
*/
@ViewChild('toggleButton') toggleButton: ElementRef;
@ViewChild('menu') menu: ElementRef;
constructor(private renderer: Renderer2) {
/**
* This events get called by all clicks on the page
*/
this.renderer.listen('window', 'click',(e:Event)=>{
/**
* Only run when toggleButton is not clicked
* If we don't check this, all clicks (even on the toggle button) gets into this
* section which in the result we might never see the menu open!
* And the menu itself is checked here, and it's where we check just outside of
* the menu and button the condition abbove must close the menu
*/
if(e.target !== this.toggleButton.nativeElement && e.target!==this.menu.nativeElement){
this.isMenuOpen=false;
}
});
}
isMenuOpen = false;
toggleMenu() {
this.isMenuOpen = !this.isMenuOpen;
}
}
Again, if you like to see the working demo, use this link: Stackblitz Demo
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';
}
}
A working example - click here
Click outside angular component
I used a directive to a similar situation.
To install:
npm install --save ng-click-outside
Then import in your module
import { ClickOutsideModule } from 'ng-click-outside';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, ClickOutsideModule],
bootstrap: [AppComponent]
})
class AppModule {}
In your component
@Component({
selector: 'app',
template: `
<div (clickOutside)="onClickedOutside($event)">Click outside this</div>
`
})
export class AppComponent {
onClickedOutside(e: Event) {
console.log('Clicked outside:', e);
}
}
It has some options. You can see it in https://www.npmjs.com/package/ng-click-outside
Regards
Angular 6 - click outside menu
As suggested in this answer, you can detect the document click
events with HostListener
. To make sure that mouse clicks don't reach the document when the menu is clicked, you should stop the propagation of the event in the click
event handler set on the aside
element:
<aside [hidden]="!menu" (click)="handleAsideClick($event)">
@HostListener('document:click', ['$event']) clickout(event) {
// Click outside of the menu was detected
...
}
handleAsideClick(event: Event) {
event.stopPropagation(); // Stop the propagation to prevent reaching document
...
}
detect when a child component is clicked outside
Use stopPropagation
event
app.html
<div (click)="fn_selectIndex($event, -1)" style="height:100vh">
<ng-container *ngFor="let item of myArray; let i=index" >
<mycomponent (click)="fn_selectIndex($event, i)" [myArray]="item" [indexSelected]="indexSelected" [index]="i"></mycomponent>
<br>
</ng-container>
</div>
app.ts
export class AppComponent {
name = 'Angular';
myArray:any=[1,2,3,4,5];
indexSelected=null;s
fn_selectIndex(event, i:any){
this.indexSelected=i;
event.stopPropagation();
}
}
Reference: https://stackblitz.com/edit/angular-edld9f?file=src/app/app.component.ts
Detect click outside of Angular application which runs in an iframe
Thanks @Msk Satheesh and @MikeOne, with the hints of both of you guys combined I got it running!
The thing is that I can really address the (outer) wordpress page by window.parent
. But this only works because both run in the same domain. Combined with the code Msk Satheesh posted in his first comment it works. And I don't even need to run anything outside of Angular. In my modal dialog component in Angular I put the following code:
constructor(public dialogRef: MatDialogRef<ResultsDialogComponent>, private eRef: ElementRef) {}
ngOnInit(): void {
if(!this.onDocumentClickFunction){
this.onDocumentClickFunction = this.onDocumentClick.bind(this);
}
window.parent.addEventListener( 'click', this.onDocumentClickFunction );
}
onDocumentClick() {
this.dialogRef.close();
this.eRef.nativeElement.click();
}
ngOnDestroy() {
window.parent.removeEventListener( 'click', this.onDocumentClickFunction );
}
And that's it. The elegant thing is that the onDocumentClick()
only fires if the click is outside the iFrame. That means I don't need additional logic to find out if the click is inside or outside the iFrame. The line this.eRef.nativeElement.click();
is necessary to bring back the focus to the iFrame. Without that line the modal only disappears if the user clicks into the iFrame himself.
Related Topics
Why Don't Svg Images Scale Using The CSS "Width" Property
Align Flex Items with Different Heights in The Same Container
Why Are Horizontal Scroll Bars Shown on My Website
Show My Location on Google Maps API V3
HTML 5 Page Without Main <Header>
HTML: How to Retain Formatting in Textarea
How to Combine Multiple CSS Rules
Why Is My Element Not Sticking to The Left When Using Position Sticky in CSS
HTML List Isn't Vertically Aligned When Using Floating Images
Why Setting Absolutely Positioned Element's Sibling as Position:Relative, Brings It Above The Former
Fill a Div with an Image Respecting Aspect Ratio
Where Is The Visual Studio HTML Designer
How to Set Different Colors in HTML in One Statement
How to Display HTML Tags as Text
Extract Content of Div from Google Translate with Vba
Center <Img/> Inside a <Div> with CSS
Open PDF File in New Window from Variable Path Name in Gsp Page