Ich habe eine Direktive mit einem isolierten Gültigkeitsbereich (damit ich die Direktive an anderen Stellen wiederverwenden kann), und wenn ich diese Direktive mit einem verwende ng-repeat
, funktioniert sie nicht.
Ich habe die gesamte Dokumentation und die Antworten zum Stapelüberlauf zu diesem Thema gelesen und verstehe die Probleme. Ich glaube, ich habe alle üblichen Fallstricke vermieden.
Ich verstehe also, dass mein Code aufgrund des durch die ng-repeat
Direktive erstellten Bereichs fehlschlägt . Meine eigene Direktive erstellt einen Isolate-Scope und führt eine bidirektionale Datenbindung an ein Objekt im übergeordneten Scope durch. Meine Direktive weist dieser gebundenen Variablen einen neuen Objektwert zu. Dies funktioniert einwandfrei, wenn meine Direktive ohne verwendet wird ng-repeat
(die übergeordnete Variable wird korrekt aktualisiert). Mit ng-repeat
erstellt die Zuweisung jedoch eine neue Variable im ng-repeat
Bereich und die übergeordnete Variable sieht die Änderung nicht. All dies basiert wie erwartet auf dem, was ich gelesen habe.
Ich habe auch gelesen, dass bei mehreren Anweisungen für ein bestimmtes Element nur ein Bereich erstellt wird. Und dass priority
in jeder Direktive ein a gesetzt werden kann, um die Reihenfolge zu definieren, in der die Direktiven angewendet werden; Die Anweisungen werden nach Priorität sortiert und anschließend ihre Kompilierungsfunktionen aufgerufen (Suche nach dem Wort Priorität unter http://docs.angularjs.org/guide/directive ).
Ich hatte gehofft, dass ich die Priorität verwenden kann, um sicherzustellen, dass meine Direktive zuerst ausgeführt wird und am Ende einen isolierten Bereich erstellt. Wenn ng-repeat
sie ausgeführt wird, wird der isolierte Bereich wiederverwendet, anstatt einen Bereich zu erstellen, der prototypisch vom übergeordneten Bereich erbt. In der ng-repeat
Dokumentation heißt es, dass diese Richtlinie auf Prioritätsebene ausgeführt wird 1000
. Es ist nicht klar, ob 1
es sich um eine höhere oder eine niedrigere Prioritätsstufe handelt. Als ich 1
in meiner Direktive die Prioritätsstufe verwendet habe, hat dies keinen Unterschied gemacht, also habe ich es versucht 2000
. Aber das macht die Sache noch schlimmer: Meine wechselseitigen Bindungen werden undefined
und meine Direktive zeigt nichts an.
Ich habe eine Geige erstellt, um mein Problem zu zeigen . Ich habe die priority
Einstellung in meiner Richtlinie auskommentiert. Ich habe eine Liste von Namensobjekten und eine Direktive namens name-row
, die die Vor- und Nachnamenfelder im Namensobjekt anzeigt. Wenn auf einen angezeigten Namen geklickt wird, soll eine selected
Variable im Hauptbereich festgelegt werden. Das Array von Namen und die selected
Variable werden name-row
mithilfe der bidirektionalen Datenbindung an die Direktive übergeben.
Ich weiß, wie dies funktioniert, indem Funktionen im Hauptbereich aufgerufen werden. Ich weiß auch, dass selected
Dinge funktionieren würden , wenn sie sich in einem anderen Objekt befinden und ich mich an das äußere Objekt binde. Aber ich bin im Moment nicht an diesen Lösungen interessiert.
Stattdessen habe ich folgende Fragen:
- Wie kann ich verhindern,
ng-repeat
dass ein Bereich erstellt wird, der prototypisch vom übergeordneten Bereich erbt, und stattdessen den Isolate-Bereich meiner Direktive verwenden? - Warum
2000
funktioniert die Prioritätsstufe in meiner Richtlinie nicht? - Ist es mit Batarang möglich zu wissen, welche Art von Oszilloskop verwendet wird?
scope: true
für Ihre Direktive. Siehe auch (falls Sie dies noch nicht getan haben) stackoverflow.com/questions/14914213/… Nur weil eine Direktive an mehreren Stellen verwendet wird, bedeutet dies nicht, dass wir automatisch einen isolierten Bereich verwenden sollten.ng-repeat
. Ich denke, es ist wertvoll, eigenständige Direktiven mit mischen zu könnenng-repeat
. Fortsetzungng-repeat
sollte dies keinen Gültigkeitsbereich haben.ng-repeat
Ein Geltungsbereich ist für den typischen Anwendungsfall sinnvoll, daher schlage ich nicht vor, ihn zu ändern. Stattdessen denke ich, wie ich in Alex Osborns Antwort kommentiert habe, dass ich eine Wiederholungsanweisung erstellen werde, die darauf basiert undng-repeat
keinen eigenen Geltungsbereich schafft. Dies kann dann zum Wiederholen von Anweisungen verwendet werden, die ihre eigenen Isolatbereiche haben. Fortsetzungng-repeat
oder die benutzerdefinierte Wiederholungsanweisung ohne Gültigkeitsbereich. Ich denke, es ist in Ordnung, wenn der "Anrufer" dies weiß, aber es ist nicht in Ordnung, wenn ein "Angerufener" (die Anweisung wird wiederholt) weiß, ob er wiederholt wird oder nicht. FortsetzungAntworten:
Okay, durch viele der obigen Kommentare habe ich die Verwirrung entdeckt. Zunächst einige Klarstellungen:
Hier ist ein Beispiel für denselben Code, wobei die Direktive entfernt wurde:
Hier ist eine JSFiddle, die zeigt, dass es nicht funktioniert. Sie erhalten genau die gleichen Ergebnisse wie in Ihrer Richtlinie.
Warum funktioniert es nicht? Weil Bereiche in AngularJS prototypische Vererbung verwenden. Der Wert
selected
in Ihrem übergeordneten Bereich ist ein Grundelement . In JavaScript bedeutet dies, dass es überschrieben wird, wenn ein untergeordnetes Element denselben Wert festlegt. In AngularJS-Bereichen gibt es eine goldene Regel: Modellwerte sollten immer verwendet werden mit einem versehen.
sein. Das heißt, sie sollten niemals primitiv sein. Weitere Informationen finden Sie in dieser SO-Antwort .Hier ist ein Bild davon, wie die Bereiche zunächst aussehen.
Nach dem Klicken auf das erste Element sehen die Bereiche nun folgendermaßen aus:
Beachten Sie, dass
selected
im Bereich ngRepeat eine neue Eigenschaft erstellt wurde. Der Controller-Bereich 003 wurde nicht geändert.Sie können wahrscheinlich erraten, was passiert, wenn wir auf den zweiten Punkt klicken:
Ihr Problem wird also überhaupt nicht durch ngRepeat verursacht, sondern durch das Brechen einer goldenen Regel in AngularJS. Die Möglichkeit, dies zu beheben, besteht darin, einfach eine Objekteigenschaft zu verwenden:
Hier ist eine zweite JSFiddle zeigt, dass dies auch funktioniert.
So sehen die Bereiche zunächst aus:
Nach dem Klicken auf den ersten Eintrag:
Hier wird der Controller-Bereich wie gewünscht beeinflusst.
Um zu beweisen, dass dies weiterhin mit Ihrer Direktive mit einem isolierten Bereich funktioniert (da dies wiederum nichts mit Ihrem Problem zu tun hat), ist hier auch eine JSFiddle , die Ansicht muss das Objekt widerspiegeln. Sie werden feststellen, dass die einzige notwendige Änderung darin bestand, ein Objekt anstelle eines Grundelements zu verwenden .
Geltungsbereich zunächst:
Geltungsbereich nach dem Klicken auf das erste Element:
Fazit: Auch hier liegt Ihr Problem nicht im isolierten Bereich und nicht in der Funktionsweise von ngRepeat. Ihr Problem ist, dass Sie gegen eine Regel verstoßen, von der bekannt ist, dass sie genau zu diesem Problem führt. Modelle in AngularJS sollten immer eine haben
.
.quelle
.
goldene Regel nur für Scopes mit prototypischer Vererbung erforderlich ist. Bei Isolate-Scopes werden die Variablen, an denen Sie interessiert sind, in derscope: {}
Definition in der Direktive definiert, und daher sind diese Variablen von Anfang an im Isolate-Scope vorhanden. Außerdem maskieren sie die übergeordneten Variablen nicht, da der Isolatbereich nicht prototypisch vom übergeordneten Bereich erbt. dh es gibt keinen "übergeordneten" Bereich zum Maskieren..
.Schauen Sie sich stattdessen die folgende Geige an, ohne direkt zu versuchen, die Beantwortung Ihrer Fragen zu vermeiden:
http://jsfiddle.net/dVPLM/
Der entscheidende Punkt ist, dass Sie, anstatt zu versuchen, das konventionelle Verhalten von Angular zu bekämpfen und zu ändern, Ihre Direktive so strukturieren können, dass Sie damit arbeiten, anstatt
ng-repeat
zu versuchen, sie zu überschreiben.In Ihrer Vorlage:
In Ihrer Richtlinie:
Als Antwort auf Ihre Fragen:
ng-repeat
Wenn Sie einen Bereich erstellen, sollten Sie wirklich nicht versuchen, dies zu ändern.quelle
ng-repeat
oder nicht. Vielleicht wird es beim ersten Schreiben nie verwendetng-repeat
. Und irgendwann in der Zukunft könnte es sich daran gewöhnenng-repeat
, und zu diesem Zeitpunkt sollte es einfach ohne Umschreiben funktionieren. Hoffentlich wird eine zukünftige Version von AngularJS dies ermöglichen.ng-repeat
oder nicht. Es scheint jedoch, dass ich eine Funktion an die Direktive übergeben müsste, damit sie die Variablen im übergeordneten Bereich ändern kann, anstatt eine bidirektionale Bindung im eigenen Bereich der Direktive mutieren zu können. Zwei-Wege-Bindungs- und wiederverwendbare Anweisungen sind meine beiden Lieblingssachen bei AngularJS undng-repeat
erweisen sich als eine Fliege in der Salbe. Vielleicht kann ich einng-repeat
Äquivalent schreiben , das keinen eigenen Bereich schafft.