2017-04-05 3 views
0

J'ai une directive qui permet de basculer l'état quand on clique dessus. Si l'état est actif et que l'utilisateur clique n'importe où sur la page, l'état doit être désactivé.Capture du prochain clic sur le document à partir de @HostListener (création dynamique d'un écouteur de clic) dans Angular 4

J'ai essayé d'y parvenir en utilisant la nouvelle fonction d'écoute Renderer2 pour générer dynamiquement un écouteur pour attraper le "clic suivant" - le problème ici est que la fonction de rappel s'exécute dès que l'écouteur est créé! Donc - un clic s'active, puis désactive immédiatement l'élément. Je cherche de l'aide pour comprendre pourquoi cela se passe et ce que je dois faire pour y remédier.

directive:

import { Directive, ElementRef, Input, Output, HostListener, EventEmitter, Renderer2 } from '@angular/core'; 

@Directive({ 
    selector: '[emClickToClose]' 
}) 
export class ClickToCloseDirective { 
    @Input('emClickToClose') 
    openCtrl: boolean; 

    @Output() 
    ctrlUpdate: EventEmitter<boolean> = new EventEmitter(); 

    @HostListener('click', ['$event']) onClick(e: MouseEvent) { 
    this.openCtrl = !this.openCtrl; 
    this.ctrlUpdate.emit(this.openCtrl); 
    if (this.openCtrl) { 
     const removeRegisteredListener = this.renderer.listen('document', 'click',() => { 
     console.log('the document was clicked', this.openCtrl); 
     this.openCtrl = false; 
     this.ctrlUpdate.emit(this.openCtrl); 
     removeRegisteredListener(); 
     }); 
    } 
    } 

    constructor(private el: ElementRef, private renderer: Renderer2) { 
    } 

} 

Répondre

1

Events bouillonner de l'enfant au parent, et que vous ajoutez un écouteur d'événement alors que l'événement est encore propagé, le document étant la société mère recevra votre événement de clic. Vous devez arrêter la propagation de l'événement en utilisant. e.stopPropagation(); dans votre gestionnaire de clics.

+0

Génial, c'était le problème! Merci –

0

Vous devez utiliser une directive et un composant pour y parvenir comme ci-dessous

déclarer le composant comme

<demo-component [emitStatus]="false"></demo-component> 

Avoir une variable d'entrée comme emitStatus

Créer une directive comme

import { Directive, HostListener, Renderer, ElementRef } from '@angular/core'; 
@Directive({ 
    selector: '[click]' 
}) 
export class ChangeDirective{ 

    constructor(
     private renderer: Renderer, 
     private el: ElementRef 
    ){} 

    @HostListener('click') onClick() { 
     let status = this.el.nativeElement.attributes['emitStatus']; 
     if(status){ 
      doo something 
     } 

    } 
} 

Ajouter le sélecteur au composant comme

<demo-component [emitStatus]="false" click></demo-component> 
+0

Hé, je suis désolé mais je ne vois pas comment votre proposition de directive atteindra ce que j'essaie de faire ici - cela n'atteindra pas la deuxième partie importante qui est mon problème principal. –

+0

pouvez-vous m'expliquer. – Aravind

0

premier votre @HostListener('click', ...) va lier un écouteur d'événement au l'élément dom que le [emClickToClose] attribut est appliqué. Je ne suis pas sûr de la façon dont vous utilisez ceci, mais si c'est la même chose que l'élément que vous voulez cliquer en dehors de pour fermer, vous devrez utiliser @HostListener('document:click', ...) à la place.

Qu'est-ce qui se passe, c'est que le gestionnaire d'événements vous lie, attrape le clic et ferme immédiatement la fenêtre, et se supprime. Vous devez vous assurer que le clic provient de l'extérieur de l'élément de votre directive, comme ceci:

import {Directive, ElementRef, Entrée, Sortie, HostListener, EventEmitter, Renderer2} à partir de '@ angular/core';

@Directive({ 
    selector: '[emClickToClose]' 
}) 
export class ClickToCloseDirective { 
    @HostListener('document:click', ['$event']) documentClick(event) { 
    if (! this.el.nativeElement.contains(event.target) && this.open) { 
     this.openCtrl = false; 
     this.ctrlUpdate.emit(this.openCtrl); 
    } 
    } 

    constructor(private el: ElementRef, private renderer: Renderer2) { 
    } 
} 

De plus, il suffit de nommer votre fonction « removeRegisteredListener » ne fera pas réellement supprimer l'écouteur d'événement, mais l'écouteur d'événement sera supprimé, lorsque la directive est détruite. J'espère que cette aide

+0

J'appelle removeRegisteredListener lorsque l'écouteur est appelé car il s'agit d'une situation d'exécution unique. L'appel de la valeur renvoyée à partir d'un écouteur de rendu supprime l'écouteur. Je dois ajouter le contrôle si le deuxième clic n'est pas dans l'élément lui-même bien sûr - la réponse à mon problème a dû faire avec le clic se propageant de mon auditeur au niveau de document après que j'avais enregistré un nouvel auditeur à le clic au niveau du document. Personnellement.Puisque cette directive peut être utilisée plusieurs fois sur la page, je ne veux pas que chaque instance ait un écouteur ouvert sur le document. –