Wie kann ich ein Dropdown-Menü schließen, wenn ich auf "Außerhalb" klicke?

Ich möchte mein Anmeldemenü-Dropdown 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 einfacheren 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 auf "sichtbar" gesetzt wird (z. B. wenn der Benutzer auf eine Schaltfläche klickt, um sie anzuzeigen), abonniert sie ein "globales" rxjs-SubjektBenutzermen im @ gespeiche SubjectsService.Und jedes Mal, wenn es ausgeblendet wird, wird das Abonnement für dieses Thema beendet.Jeder Klick irgendwoinnerhal das Template dieser Komponente löst dasonClick () -Methode, die das Sprudeln von Ereignissen nach oben (und zur Anwendungskomponente) einfach stoppt.

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 ein übergeordnetes Element der Dropdown-Komponente ist):

Diese Komponente fängt jedes Klickereignis ab und gibt es auf demselben RXJS-Betreff aus Benutzermen)

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 Verbindungselement 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.Die Dropdown-Liste wird angezeigt undes abonniert sofort den UserMenu Betreff.Das Klickereignis sprudelt bis zur App-Komponente und wird abgefangenDie Anwendungskomponente sendet ein Ereignis auf demBenutzermen GegenstanDie Dropdown-Komponente fängt diese Aktion aufBenutzermen und verstecke das Dropdown.Am Ende wird die Dropdown-Liste nie angezeigt.

Diese eingestellte Zeitüberschreitung verzögert das Abonnement bis zum Ende der aktuellen JavaScript-Code-Umdrehung, was das Problem löst, 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 :)!

Antworten auf die Frage(36)

Ihre Antwort auf die Frage