Ich möchte mein Dropdown-Menü für das Anmeldemenü schließen, wenn der Benutzer auf eine beliebige Stelle außerhalb dieses Dropdowns klickt, und ich möchte dies mit Angular2 und dem Angular2-Ansatz tun ...
Ich habe eine Lösung implementiert, bin aber nicht sicher. Ich denke, es muss einen einfachsten Weg geben, um das gleiche Ergebnis zu erzielen. Wenn Sie also Ideen haben ... lassen Sie uns darüber diskutieren :)!
Hier ist meine Implementierung:
Die Dropdown-Komponente:
Dies ist die Komponente für mein Dropdown:
- Jedes Mal, wenn diese Komponente sichtbar wird (z. B. wenn der Benutzer auf eine Schaltfläche klickt, um sie anzuzeigen), abonniert sie ein "globales" rxjs-Betreff userMenu, das im SubjectsService gespeichert ist .
- Und jedes Mal, wenn es versteckt ist, wird dieses Thema abgemeldet.
- Jeder Klick irgendwo in der Vorlage dieser Komponente löst die onClick () -Methode aus, die einfach verhindert, dass das Ereignis nach oben sprudelt (und die Anwendungskomponente).
Hier ist der 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;
}
}
Die Anwendungskomponente:
Auf der anderen Seite gibt es die Anwendungskomponente (die der Dropdown-Komponente übergeordnet ist):
- Diese Komponente fängt jedes Klickereignis ab und sendet auf demselben rxjs-Betreff ( userMenu ).
Hier ist der Code:
export class AppComponent {
constructor( public subjects: SubjectsService) {
document.addEventListener('click', () => this.onClick());
}
onClick( ) {
this.subjects.userMenu.next({});
}
}
Was mich stört:
- Ich fühle mich nicht wirklich wohl mit der Idee, ein globales Thema zu haben, das als Bindeglied zwischen diesen Komponenten fungiert.
- Das setTimeout : Dies ist erforderlich, da Folgendes passiert, wenn der Benutzer auf die Schaltfläche klickt, die das Dropdown-Menü anzeigt:
- Der Benutzer klickt auf die Schaltfläche (die nicht Teil der Dropdown-Komponente ist), um die Dropdown-Liste anzuzeigen.
- Das Dropdown-Menü wird angezeigt und abonniert sofort den Betreff userMenu .
- Das Klickereignis sprudelt zur App-Komponente und wird abgefangen
- Die Anwendungskomponente emittieren , ein Ereignis auf dem UserMenu Subjekt
- Die Dropdown-Komponente fängt diese Aktion im Benutzermenü ab und blendet das Dropdown aus.
- Am Ende wird das Dropdown nie angezeigt.
Diese festgelegte Zeitüberschreitung verzögert das Abonnement bis zum Ende der aktuellen JavaScript-Code-Runde, wodurch das Problem gelöst wird, aber meiner Meinung nach auf sehr elegante Weise.
Wenn Sie sauberere, bessere, intelligentere, schnellere oder stärkere Lösungen kennen, lassen Sie es mich bitte wissen :)!