Vorrei chiudere il menu a discesa del menu di accesso quando l'utente fa clic in un punto qualsiasi al di fuori di tale menu a discesa e mi piacerebbe farlo con Angular2 e con l'approccio "Angular2" ...
Ho implementato una soluzione, ma in realtà non mi sento sicuro. Penso che ci debba essere un modo più semplice per ottenere lo stesso risultato, quindi se hai qualche idea ... discutiamo :)!
Ecco la mia implementazione:
Il componente a discesa:
Questo è il componente per il mio menu a discesa:
- Ogni volta che questo componente è impostato su visibile, (per esempio: quando l'utente fa clic su un pulsante per visualizzare esso) è la sottoscrizione di un "globale" rxjs soggetto usermenu memorizzati all'interno del SubjectsService .
- E ogni volta che è nascosto, annulla l'iscrizione a questo argomento.
- Ogni clic in qualsiasi punto all'interno del modello di questo componente attiva il metodo onClick () , che interrompe appena il gorgoglio degli eventi verso l'alto (e il componente dell'applicazione)
Ecco il codice
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;
}
}
Il componente dell'applicazione:
D'altra parte, c'è il componente dell'applicazione (che è un genitore del componente a discesa):
- Questo componente cattura ogni evento click ed emette sullo stesso oggetto rxjs ( userMenu )
Ecco il codice:
export class AppComponent {
constructor( public subjects: SubjectsService) {
document.addEventListener('click', () => this.onClick());
}
onClick( ) {
this.subjects.userMenu.next({});
}
}
Cosa mi dà fastidio:
- Non mi sento davvero a mio agio con l'idea di avere un soggetto globale che funga da connettore tra quei componenti.
- Il setTimeout : questo è necessario perché ecco cosa succede altrimenti se l'utente fa clic sul pulsante che mostra il menu a discesa:
- L'utente fa clic sul pulsante (che non fa parte del componente a discesa) per mostrare il menu a discesa.
- Viene visualizzato il menu a discesa e si iscrive immediatamente all'oggetto Menù utente .
- L'evento click arriva al componente dell'app e viene catturato
- Il componente dell'applicazione emette un evento sull'argomento userMenu
- Il componente a discesa cattura questa azione sul menu utente e nasconde il menu a discesa.
- Alla fine il menu a discesa non viene mai visualizzato.
Questo timeout impostato ritarda l'abbonamento alla fine dell'attuale turno del codice JavaScript che risolve il problema, ma secondo me in modo molto elegante.
Se conosci soluzioni più pulite, migliori, più intelligenti, più veloci o più forti, faccelo sapere :)!