Wie kann ich eine AngularJS-Direktive erstellen, um StopPropagation zu stoppen?

76

Ich versuche, "stopPropagation" zu stoppen, um zu verhindern, dass ein Dropdown-Menü der Twitter-Bootstrap-Navigationsleiste geschlossen wird, wenn auf ein Element (Link) in einem Li geklickt wird. Die Verwendung dieser Methode scheint die übliche Lösung zu sein .

Scheint in Angular eine Richtlinie der Ort zu sein, um dies zu tun? Also habe ich:

// do not close dropdown on click
directives.directive('stopPropagation', function () {
    return {
        link:function (elm) {            
            $(elm).click(function (event) {                
                event.stopPropagation();
            });
        }
    };
});

... aber die Methode gehört nicht zum Element:

TypeError: Object [object Object] has no method 'stopPropagation'

Ich binde die Richtlinie mit

<li ng-repeat="foo in bar">
  <div>
    {{foo.text}}<a stop-propagation ng-click="doThing($index)">clickme</a>
  </div>
</li>

Irgendwelche Vorschläge?

Robert Christian
quelle
Sie sollten in den Tags etwas Platz für Javascript (oder sogar JQuery ) schaffen.
Joseph Silber
Guter Vorschlag. Die Bearbeitung vorgenommen.
Robert Christian
Der Grund, warum event.stopPropagation()dies in Ihrem Code nicht funktioniert, ist, dass AngularJS und jQuery zwei separate Ereigniszyklen haben . Das ist ein Grund, warum es im Allgemeinen eine schlechte Idee ist, beide zu verwenden. Ihr mit definiertes ngClickKlickereignis verwendet Angular, aber Sie versuchen, mit jQuery die Ereignisausbreitung zu stoppen.
Josh David Miller

Antworten:

156

Ich habe diesen Weg benutzt: Erstellt eine Direktive:

    .directive('stopEvent', function () {
        return {
            restrict: 'A',
            link: function (scope, element, attr) {
                if(attr && attr.stopEvent)
                    element.bind(attr.stopEvent, function (e) {
                        e.stopPropagation();
                    });
            }
        };
     });

das könnte so verwendet werden:

<a ng-click='expression' stop-event='click'>

Dies ist eine allgemeinere Methode, um die Weitergabe von Ereignissen jeglicher Art zu stoppen.

Valentyn Shybanov
quelle
Übrigens, können Sie das Schlüsselwort "Beschränken" näher erläutern? Keine gute Ressource für das zu finden, was das genau bedeutet.
Robert Christian
Sicher! docs.angularjs.org/guide/directive "Direktivendefinitionsobjekt": einschränken - Zeichenfolge einer Teilmenge von EACM, die die Direktive auf einen bestimmten Deklarationsstil für Direktiven beschränkt. Wenn ausgelassene Anweisungen nur für Attribute zulässig sind.
Valentyn Shybanov
Dies ist ein interessanter Ansatz ... Ich mag es. Vielen Dank!
Incutonez
1
Dieselbe Lösung für .prefentDefault () in IE7, um das Neuladen von Seiten zu verhindern. Tolle Lösung!
Malkus
1
Oh Herr, ich liebe Anweisungen
Deminetix
123

"Derzeit stoppen einige Anweisungen (z. B. ng: click) die Ereignisausbreitung. Dies verhindert die Interoperabilität mit anderen Frameworks, die auf der Erfassung solcher Ereignisse beruhen." - Link

... und konnte ohne Anweisung beheben und einfach Folgendes tun:

<a ng-click="doThing($index); $event.stopPropagation();">x</a>
Robert Christian
quelle
4
Das war perfekt. Ich hatte ein Dropdown mit einem Formular. Ich habe ng-click = "$ event.stopPropagation ()" zum div um das Formular hinzugefügt und das Dropdown-Menü wurde entfernt, wenn auf die Formulareingaben geklickt wurde. Vielen Dank!
Thaspius
einfache Lösung. hat perfekt funktioniert. Ich würde dies vorziehen, anstatt eine Richtlinie zu erstellen.
Nithin Emmanuel
In der Tat einfacher als eine Richtlinie erstellen zu müssen. funktioniert gut für mich. Danke
estellechvl
3
Einfach für ein Einweg-Szenario. Ich würde jedem empfehlen, der diesen Code an mehreren Stellen in der Ansicht verwenden muss, eine Direktive zu verwenden. Zum einen ist es einfacher, die Funktionalität zu erweitern, mehr Ereignisse zu verarbeiten und insbesondere zu versuchen, die Logik so weit wie möglich aus dem Markup herauszuhalten möglich. Prost!
Danny Bullis
Diese Strategie funktioniert nicht, wenn wir auf eine andere Schaltfläche klicken, Link. Der aktuelle Link wird nicht geschlossen
Saurabh
9

stopPropagationmuss für ein Ereignisobjekt aufgerufen werden, nicht für das Element selbst. Hier ist ein Beispiel:

compile: function (elm) {
    return function (scope, elm, attrs) {
        $(elm).click(function (event) {
            event.stopPropagation();
        });
    };
}
Joseph Silber
quelle
Vielen Dank. Ich habe die Frage so bearbeitet, dass die Direktive stopPropagation für Ereignis und nicht für Element aufruft. Hat nicht funktioniert. Folgendes wurde gefunden: "Derzeit stoppen einige Anweisungen (z. B. ng: click) die Ereignisausbreitung. Dies verhindert die Interoperabilität mit anderen Frameworks, die die Erfassung solcher Ereignisse erfordern." - - github.com/angular/angular.js/issues/259
Robert Christian
Also fand ich, dass dies das Problem ist: <a ng-click="doThing($index); $event.stopPropagation();"> x </a>
Robert Christian
1

Hier ist eine einfache, abstrakte Anweisung, um die Weitergabe von Ereignissen zu stoppen. Ich denke, es könnte für jemanden nützlich sein. Übergeben Sie einfach den Fall, dass Sie aufhören möchten.

<div stopProp="click"></div>

app.directive('stopProp', function () {
  return function (scope, elm, attrs) {
    elm.on(attrs.stopProp, function (event) {
        event.stopPropagation();
    });
  };
});

Vinny
quelle
2
Müsste das nicht stop-propim Element sein?
Pete