Me gustaría cerrar mi menú desplegable de inicio de sesión cuando el usuario haga clic en cualquier lugar fuera de ese menú desplegable, y me gustaría hacerlo con Angular2 y con el "enfoque" de Angular2 ...
He implementado una solución, pero realmente no me siento seguro con ella. Creo que debe haber una manera más fácil de lograr el mismo resultado, así que si tienes alguna idea ... ¡discutamos :)!
Aquí está mi implementación:
El componente desplegable:
Este es el componente para mi menú desplegable:
- Cada vez que este componente se establece en visible, (por ejemplo: cuando el usuario hace clic en un botón para mostrarlo) se suscribe a un sujeto de usuario "global" rxjs almacenado en el servicio de sujetos .
- Y cada vez que está oculto, se da de baja de este tema.
- Cada clic en cualquier lugar dentro de la plantilla de este componente activa el método onClick () , que simplemente detiene el burbujeo de eventos en la parte superior (y el componente de la aplicación)
Aqui esta el codigo
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;
}
}
El componente de la aplicación:
Por otro lado, está el componente de la aplicación (que es un padre del componente desplegable):
- Este componente captura cada evento de clic y emite en el mismo Asunto rxjs ( userMenu )
Aquí está el código:
export class AppComponent {
constructor( public subjects: SubjectsService) {
document.addEventListener('click', () => this.onClick());
}
onClick( ) {
this.subjects.userMenu.next({});
}
}
Lo que me molesta:
- No me siento realmente cómodo con la idea de tener un Sujeto global que actúe como conector entre esos componentes.
- El setTimeout : Esto es necesario porque esto es lo que sucede lo contrario, si el usuario pulsa en el botón que muestra el menú desplegable:
- El usuario hace clic en el botón (que no es parte del componente desplegable) para mostrar el menú desplegable.
- Se muestra el menú desplegable e inmediatamente se suscribe al asunto UserMenu .
- El evento de clic aparece en el componente de la aplicación y queda atrapado
- El componente de la aplicación emite un evento sobre el tema userMenu
- El componente desplegable captura esta acción en userMenu y oculta el menú desplegable.
- Al final, el menú desplegable nunca se muestra.
Este tiempo de espera establecido retrasa la suscripción al final del código JavaScript actual que resuelve el problema, pero en una forma muy elegante en mi opinión.
Si conoce soluciones más limpias, mejores, más inteligentes, más rápidas o más fuertes, ¡hágamelo saber :)!