Como posso fechar uma lista suspensa ao clicar fora?
Gostaria de fechar meu menu suspenso de login quando o usuário clicar em qualquer lugar fora desse menu suspenso e gostaria de fazer isso com o Angular2 e com a "abordagem" do Angular2 ...
Eu implementei uma solução, mas realmente não me sinto confiante com ela. Eu acho que deve haver uma maneira mais fácil de obter o mesmo resultado, então se você tiver alguma idéia ... vamos discutir :)!
Aqui está a minha implementação:
O componente suspenso:Este é o componente do meu menu suspenso:
Sempre que esse componente é definido como visível (por exemplo: quando o usuário clica em um botão para exibi-lo), ele assina um assunto rxjs "global"menu do usuário armazenado dentro doAssuntosServiço.E toda vez que está oculto, cancela a inscrição neste assunto.Cada clique em qualquer lugardentro o modelo deste componente aciona oonClick () método, que apenas interrompe a subida do evento até o topo (e o componente do aplicativo)Aqui está o código
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;
}
}
O componente do aplicativo:Por outro lado, existe o componente de aplicativo (que é o pai do componente suspenso):
Este componente captura todos os eventos de clique e emite no mesmo assunto rxjs (menu do usuário)Aqui está o código:
export class AppComponent {
constructor( public subjects: SubjectsService) {
document.addEventListener('click', () => this.onClick());
}
onClick( ) {
this.subjects.userMenu.next({});
}
}
O que me incomoda:Não me sinto muito à vontade com a ideia de ter um Assunto global que atue como o conector entre esses componentes.osetTimeout: Isso é necessário porque é o que acontece caso contrário, se o usuário clicar no botão que mostra o menu suspenso:O usuário clica no botão (que não faz parte do componente suspenso) para mostrar o menu suspenso.O menu suspenso é exibido eele se inscreve imediatamente no assunto userMenu.O evento click clica no componente do aplicativo e é capturadoO componente de aplicativo emite um evento nomenu do usuário sujeitoO componente suspenso captura essa ação emmenu do usuário e oculte o menu suspenso.No final, o menu suspenso nunca é exibido.Esse tempo limite definido atrasa a assinatura até o final do código JavaScript atual, que resolve o problema, mas de uma maneira muito elegante na minha opinião.
Se você souber soluções mais limpas, melhores, mais inteligentes, mais rápidas ou mais fortes, entre em contato :)!