Je voudrais fermer ma liste déroulante de menu de connexion lorsque l'utilisateur clique n'importe où en dehors de cette liste déroulante, et j'aimerais le faire avec Angular2 et avec "l'approche" Angular2 ...
J'ai mis en place une solution, mais je ne me sens vraiment pas en confiance. Je pense qu'il doit y avoir un moyen le plus simple d'obtenir le même résultat, donc si vous avez des idées ... discutons-en :)!
Voici ma mise en œuvre:
Le composant déroulant:
C'est le composant de ma liste déroulante:
- Chaque fois que ce composant est défini sur visible, (par exemple: lorsque l'utilisateur clique sur un bouton pour l'afficher), il s'abonne à un userMenu "global" sujet rxjs stocké dans le SubjectsService .
- Et chaque fois qu'il est caché, il se désabonne à ce sujet.
- Chaque clic n'importe où dans le modèle de ce composant déclenche la méthode onClick () , qui arrête simplement l'événement de remonter vers le haut (et le composant d'application)
Voici le code
export class UserMenuComponent {
_isVisible: boolean = false;
_subscriptions: Subscription<any> = null;
constructor(public subjects: SubjectsService) {
}
onClick(event) {
event.stopPropagation();
}
set isVisible(v) {
if( v ){
setTimeout( () => {
this._subscriptions = this.subjects.userMenu.subscribe((e) => {
this.isVisible = false;
})
}, 0);
} else {
this._subscriptions.unsubscribe();
}
this._isVisible = v;
}
get isVisible() {
return this._isVisible;
}
}
Le composant applicatif:
D'autre part, il y a le composant d'application (qui est un parent du composant déroulant):
- Ce composant capture chaque événement de clic et émet sur le même sujet rxjs ( userMenu )
Voici le code:
export class AppComponent {
constructor( public subjects: SubjectsService) {
document.addEventListener('click', () => this.onClick());
}
onClick( ) {
this.subjects.userMenu.next({});
}
}
Ce qui me dérange:
- Je ne me sens pas vraiment à l'aise avec l'idée d'avoir un sujet global qui fasse office de connecteur entre ces composants.
- Le setTimeout : Ceci est nécessaire car voici ce qui se passe sinon si l'utilisateur clique sur le bouton qui affiche la liste déroulante:
- L'utilisateur clique sur le bouton (qui ne fait pas partie du composant déroulant) pour afficher le menu déroulant.
- La liste déroulante s'affiche et il s'abonne immédiatement à l'objet userMenu .
- L'événement de clic s'incline jusqu'au composant de l'application et se fait prendre
- Le composant application émet un événement sur le sujet userMenu
- Le composant déroulant capture cette action sur userMenu et masque la liste déroulante.
- À la fin, la liste déroulante n'est jamais affichée.
Ce délai d'expiration retardé l'abonnement à la fin du tour de code JavaScript actuel qui résout le problème, mais d'une manière très élégante à mon avis.
Si vous connaissez des solutions plus propres, meilleures, plus intelligentes, plus rapides ou plus fortes, faites-le moi savoir :)!