Saltar al contenido

¿Cómo detectar un clic fuera de un elemento en Angular?

Solución:

Aquí está el enlace a la demostración funcional: Stackblitz Demo

Haría esto utilizando el enfoque recomendado por Angular, que también es fácil de desarrollar aplicaciones en entornos sin acceso DOM, quiero decir Renderer 2 class que es una abstracción proporcionada por Angular en forma de un servicio que permite manipular elementos de su aplicación sin tener que tocar el DOM directamente.

En este enfoque, debe inyectar Renderer2 en su constructor de componentes, que el Renderer2 nos permite listen a eventos desencadenados con elegancia. Solo toma el elemento que va a escuchar como el primer argumento que puede ser window, document, body o cualquier otro elemento de referencia. Para el segundo argumento, toma el evento que vamos a escuchar, que en este caso es click, y el tercer argumento es en realidad la función de devolución de llamada que lo hacemos mediante la función de flecha.

this.renderer.listen('window', 'click',(e:Event)=>{ // your code here})

El resto de la solución es fácil, solo necesita establecer una bandera booleana que mantenga la visibilidad del estado del menú (o panel), y lo que debemos hacer es asignar false a esa bandera cuando se hace clic fuera del menú.

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;
  }
}

Nuevamente, si desea ver la demostración funcional, use este enlace: Stackblitz Demo

puedes hacer algo como esto

  @HostListener('document:mousedown', ['$event'])
  onGlobalClick(event): void {
     if (!this.elementRef.nativeElement.contains(event.target)) {
        // clicked outside => close dropdown list
     this.isOpen = false;
     }
  }

y use * ngIf = isOpen para el panel

Me gustaría agregar la solución que me ayudó a lograr el resultado adecuado.

Cuando se utilizan elementos incrustados y desea detectar un clic en el padre, event.target hace referencia al hijo básico.

HTML

<div #toggleButton (click)="toggleMenu()">
    <u>Toggle Menu</u>
    <span class="some-icon"></span>
</div>

<div #menu class="menu" *ngIf="isMenuOpen">
    <h1>I'm the menu.</h1>
    <div>
        I have some complex content containing multiple children.
        <i>Click outside to close me</i>
    </div>
</div>

Hago clic en “Alternar menú” text, event.target devuelve una referencia a ‘u’ elemento en lugar de #botón de activación div.

Para este caso utilicé la solución de M98, incluido Renderer2, pero cambié la condición a la de la respuesta de Sujay.

ToggleButton.nativeElement.contains (e.target) devuelve cierto incluso si el destino del evento de clic está en los hijos de nativeElement, lo que resuelve el problema.

componente.ts

export class AppComponent {
/**
 * This is the toogle button element, look at HTML and see its definition
 */
    @ViewChild('toggleButton') toggleButton: ElementRef;
    @ViewChild('menu') menu: ElementRef;
    isMenuOpen = false;

    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(!this.toggleButton.nativeElement.contains(e.target) && !this.menu.nativeElement.contains(e.target)) {
                this.isMenuOpen=false;
            }
        });
    }

    toggleMenu() {
        this.isMenuOpen = !this.isMenuOpen;
    }
}
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *