Ich suche nach Richtlinien, anhand derer ermittelt werden kann, welcher Bereich beim Schreiben einer neuen Richtlinie verwendet werden soll. Im Idealfall hätte ich gerne etwas Ähnliches wie ein Flussdiagramm, das mich durch eine Reihe von Fragen führt und die richtige Antwort herausgibt - kein neuer neuer Bereich, neuer untergeordneter Bereich oder neuer isolierter Bereich -, aber das verlangt wahrscheinlich zu viel. Hier sind meine aktuellen dürftigen Richtlinien:
- Verwenden Sie keinen isolierten Bereich, wenn das Element, das die Direktive verwendet, ng-model verwendet.
Siehe Kann ich ng-model mit isoliertem Bereich verwenden? und
warum arbeiten Formatierer nicht mit isoliertem Bereich? - Wenn die Direktive keine Bereichs- / Modelleigenschaften ändert, erstellen Sie keinen neuen Bereich
- Isolierte Bereiche scheinen gut zu funktionieren, wenn die Direktive eine Reihe von DOM-Elementen kapselt (in der Dokumentation heißt es "eine komplexe DOM-Struktur") und die Direktive als Element verwendet wird oder keine anderen Direktiven für dasselbe Element vorhanden sind.
Ich bin mir bewusst, dass die Verwendung einer Direktive mit einem isolierten Bereich für ein Element alle anderen Anweisungen für dasselbe Element dazu zwingt, denselben (einen) isolierten Bereich zu verwenden. Wird dies nicht stark eingeschränkt, wenn ein isolierter Bereich verwendet werden kann?
Ich hoffe, dass einige aus dem Angular-UI-Team (oder andere, die viele Richtlinien geschrieben haben) ihre Erfahrungen teilen können.
Bitte fügen Sie keine Antwort hinzu, die einfach lautet: "Verwenden Sie einen isolierten Bereich für wiederverwendbare Komponenten".
quelle
scope: true
erstellt$scope.new()
automatisch einen untergeordneten Bereich .scope: false
(Standard, kein neuer Bereich),scope: true
(neuer Bereich, der prototypisch erbt) undscope: { ... }
(neuer isolierter Bereich).Antworten:
Was für eine tolle Frage! Ich würde gerne hören, was andere zu sagen haben, aber hier sind die Richtlinien, die ich verwende.
Die Prämisse für große Höhen: Der Bereich wird als "Klebstoff" verwendet, mit dem wir zwischen dem übergeordneten Controller, der Direktive und der Direktivenvorlage kommunizieren.
Übergeordneter Bereich :
scope: false
, also überhaupt kein neuer BereichIch benutze dies nicht sehr oft, aber wie @MarkRajcok sagte, wenn die Direktive nicht auf Bereichsvariablen zugreift (und offensichtlich keine setzt!), Ist dies für mich in Ordnung. Dies ist auch hilfreich für untergeordnete Anweisungen, die nur im Kontext der übergeordneten Anweisung verwendet werden (obwohl es immer Ausnahmen gibt) und die keine Vorlage haben. Grundsätzlich gehört alles mit einer Vorlage nicht zur gemeinsamen Nutzung eines Bereichs, da Sie diesen Bereich von Natur aus für Zugriff und Manipulation verfügbar machen (aber ich bin sicher, dass es Ausnahmen von dieser Regel gibt).
Als Beispiel habe ich kürzlich eine Direktive erstellt, die eine (statische) Vektorgrafik mit einer SVG-Bibliothek zeichnet, die ich gerade schreibe. Es besteht aus
$observe
zwei Attributen (width
undheight
) und verwendet diese in seinen Berechnungen, setzt jedoch keine Bereichsvariablen und liest sie auch nicht und verfügt über keine Vorlage. Dies ist ein guter Anwendungsfall, um keinen weiteren Bereich zu erstellen. Wir brauchen keine, warum also die Mühe machen?In einer anderen SVG-Direktive benötigte ich jedoch einen Datensatz, um ihn zu verwenden, und musste zusätzlich ein kleines Stück Status speichern. In diesem Fall wäre die Verwendung des übergeordneten Bereichs unverantwortlich (wiederum im Allgemeinen). Also stattdessen...
Kinderbereich:
scope: true
Anweisungen mit einem untergeordneten Bereich sind kontextsensitiv und sollen mit dem aktuellen Bereich interagieren.
Offensichtlich besteht ein wesentlicher Vorteil gegenüber einem isolierten Bereich darin, dass der Benutzer die Interpolation für alle gewünschten Attribute verwenden kann. Die Verwendung
class="item-type-{{item.type}}"
einer Direktive mit einem isolierten Bereich funktioniert beispielsweise nicht standardmäßig, funktioniert jedoch bei einer Direktive mit einem untergeordneten Bereich einwandfrei, da alles, was interpoliert wird, standardmäßig immer noch im übergeordneten Bereich gefunden wird. Außerdem kann die Richtlinie selbst Attribute und Ausdrücke im Rahmen ihres eigenen Geltungsbereichs sicher bewerten, ohne sich um Verschmutzung oder Beschädigung des Elternteils sorgen zu müssen.Ein Tooltip wird beispielsweise gerade hinzugefügt. Ein isolierter Bereich würde nicht funktionieren (standardmäßig siehe unten), da erwartet wird, dass wir hier andere Direktiven oder interpolierte Attribute verwenden. Der Tooltip ist nur eine Erweiterung. Der Tooltip muss jedoch auch einige Dinge für den Bereich festlegen, die mit einer Unteranweisung und / oder Vorlage verwendet werden sollen, und natürlich den eigenen Status verwalten. Daher wäre es in der Tat ziemlich schlecht, den übergeordneten Bereich zu verwenden. Wir verschmutzen es entweder oder beschädigen es, und Bueno ist es auch nicht.
Ich verwende häufig untergeordnete Bereiche als isolierte oder übergeordnete Bereiche.
Bereich isolieren:
scope: {}
Dies gilt für wiederverwendbare Komponenten. :-)
Aber im Ernst, ich stelle mir "wiederverwendbare Komponenten" als "in sich geschlossene Komponenten" vor. Die Absicht ist, dass sie für einen bestimmten Zweck verwendet werden sollen. Daher ist es nicht sinnvoll, sie mit anderen Anweisungen zu kombinieren oder dem DOM-Knoten von Natur aus andere interpolierte Attribute hinzuzufügen.
Genauer gesagt wird alles, was für diese eigenständige Funktionalität benötigt wird, durch angegebene Attribute bereitgestellt, die im Kontext des übergeordneten Bereichs ausgewertet werden. Es handelt sich entweder um Einwegzeichenfolgen ('@'), Einwegausdrücke ('&') oder Zweiwegvariablenbindungen ('=').
Bei in sich geschlossenen Komponenten ist es nicht sinnvoll, andere Anweisungen oder Attribute darauf anzuwenden, da diese für sich allein existieren. Sein Stil wird von einer eigenen Vorlage bestimmt (falls erforderlich) und kann den entsprechenden Inhalt (falls erforderlich) übertragen. Es ist eigenständig, daher stellen wir es in einen isolierten Bereich, um auch zu sagen: "Leg dich nicht damit an. Ich gebe dir eine definierte API durch diese wenigen Attribute."
Eine bewährte Methode besteht darin, so viele vorlagenbasierte Inhalte wie möglich von den Funktionen für Direktivenverknüpfungen und Controller auszuschließen. Dies bietet einen weiteren "API-ähnlichen" Konfigurationspunkt: Der Benutzer der Direktive kann die Vorlage einfach ersetzen! Die Funktionalität blieb alle gleich, und die interne API wurde nie berührt, aber wir können so viel wie nötig mit dem Styling und der DOM-Implementierung herumspielen. ui / bootstrap ist ein großartiges Beispiel dafür, wie man das gut macht, weil Peter & Pawel großartig sind.
Isolierte Zielfernrohre eignen sich auch hervorragend für die Transklusion. Nehmen Sie Tabs; sie sind nicht nur die ganze Funktionalität, aber was auch immer ist im Innern davon können frei aus dem übergeordneten Bereich ausgewertet werden , während die Reiter verlassen (und Scheiben) zu tun , was sie wollen. Die Registerkarten haben eindeutig ihren eigenen Status , der zum Gültigkeitsbereich gehört (um mit der Vorlage zu interagieren), aber dieser Status hat nichts mit dem Kontext zu tun, in dem er verwendet wurde - er ist völlig intern für das, was eine Tabulatoranweisung zu einer Tabulatoranweisung macht. Außerdem ist es wenig sinnvoll, andere Anweisungen mit den Registerkarten zu verwenden. Das sind Tabs - und diese Funktionalität haben wir bereits!
Umgib es mit mehr Funktionalität oder schließe mehr Funktionalität aus, aber die Direktive ist das, was sie bereits ist.
Trotzdem sollte ich beachten, dass es einige Möglichkeiten gibt, einige der Einschränkungen (dh Funktionen) eines isolierten Bereichs zu umgehen, wie @ProLoser in seiner Antwort angedeutet hat. Im Abschnitt "Untergeordneter Bereich" habe ich beispielsweise die Interpolation von Attributen erwähnt, die bei Verwendung eines isolierten Bereichs (standardmäßig) fehlerhaft sind. Aber der Benutzer könnte zum Beispiel einfach verwenden
class="item-type-{{$parent.item.type}}"
und es würde wieder funktionieren. Wenn es also einen zwingenden Grund gibt, einen isolierten Bereich anstelle eines untergeordneten Bereichs zu verwenden, Sie sich jedoch über einige dieser Einschränkungen Sorgen machen, sollten Sie wissen, dass Sie bei Bedarf praktisch alle umgehen können.Zusammenfassung
Anweisungen ohne neuen Geltungsbereich sind schreibgeschützt. Sie sind absolut vertrauenswürdig (dh intern in der App) und berühren die Buchse nicht. Direktiven mit einem untergeordneten Bereich fügen Funktionen hinzu, sind jedoch nicht die einzigen Funktionen. Schließlich beziehen sich isolierte Bereiche auf Richtlinien, die das gesamte Ziel darstellen. Sie sind eigenständig, daher ist es in Ordnung (und am "richtigsten"), sie als Schurken zu betrachten.
Ich wollte meine ersten Gedanken herausbringen, aber wenn ich an mehr Dinge denke, werde ich dies aktualisieren. Aber heiliger Mist - das ist lang für eine SO-Antwort ...
PS: Völlig tangential, aber da es sich um Bereiche handelt, sage ich lieber "prototypisch", während andere "prototypisch" bevorzugen, was genauer zu sein scheint, aber überhaupt nicht gut von der Zunge rollt. :-)
quelle
ngInclude
. Oder machen Sie es als Teil Ihres Builds. Viele Optionen!Meine persönliche Politik und Erfahrung:
Isoliert: ein privater Sandkasten
Ich möchte viele Bereichsmethoden und -variablen erstellen, die NUR von meiner Direktive verwendet werden und vom Benutzer nie gesehen oder direkt aufgerufen werden. Ich möchte auf die Whitelist setzen, welche Bereichsdaten mir zur Verfügung stehen. Ich kann die Transklusion verwenden, um dem Benutzer zu ermöglichen, wieder in den übergeordneten Bereich zu springen (nicht betroffen) . Ich möchte NICHT, dass meine Variablen und Methoden in ausgeschlossenen Kindern zugänglich sind.
Kind: ein Unterabschnitt des Inhalts
Ich möchte Bereichsmethoden und -variablen erstellen, auf die der Benutzer zugreifen kann, die jedoch für umgebende Bereiche (Geschwister und Eltern) außerhalb des Kontexts meiner Richtlinie nicht relevant sind. Ich möchte auch, dass ALLE übergeordneten Bereichsdaten transparent herunterrinnen.
Keine: einfache, schreibgeschützte Anweisungen
Ich muss mich nicht wirklich mit Bereichsmethoden oder Variablen herumschlagen. Ich mache wahrscheinlich etwas, das nichts mit Bereichen zu tun hat (wie das Anzeigen einfacher jQuery-Plugins, Validierung usw.).
Anmerkungen
ng-model=$parent.myVal
(Kind) oderngModel: '='
(Isolieren) tun .require: '^ngModel'
in übergeordneten Elementen suchen.quelle
Nachdem ich viele Anweisungen geschrieben habe, habe ich beschlossen, weniger
isolated
Umfang zu verwenden. Obwohl es cool ist und Sie die Daten kapseln und sicherstellen, dass keine Daten in den übergeordneten Bereich gelangen, wird die Anzahl der Anweisungen, die Sie zusammen verwenden können, erheblich eingeschränkt. So,Wenn sich die Direktive, die Sie schreiben werden, vollständig von selbst verhält und Sie sie nicht mit anderen Direktiven teilen, wählen Sie einen isolierten Geltungsbereich . (Wie bei einer Komponente können Sie sie einfach anschließen, ohne dass der Endentwickler sie anpassen muss.) (Es wird sehr schwierig, wenn Sie versuchen, Unterelemente zu schreiben, in denen Anweisungen enthalten sind.)
Wenn die Direktive, die Sie schreiben werden, nur Dom-Manipulationen vornimmt, für die kein interner Geltungsbereich erforderlich ist, oder explizite Änderungen des Geltungsbereichs (meist sehr einfache Dinge); Gehen Sie für keinen neuen Bereich . (wie zum Beispiel
ngShow
,ngMouseHover
,ngClick
,ngRepeat
)Wenn die Direktive, die Sie schreiben möchten, einige Elemente im übergeordneten Bereich ändern muss, aber auch einen internen Status verarbeiten muss, wählen Sie einen neuen untergeordneten Bereich . (wie
ngController
)Lesen
Sie unbedingt den Quellcode für Anweisungen: https://github.com/angular/angular.js/tree/master/src/ng/directive Es ist sehr hilfreich, wie Sie darüber nachdenken
quelle
require
, sodass Ihre Anweisungen weiterhin entkoppelt bleiben. Wie schränkt es die Möglichkeiten ein? Dadurch werden Richtlinien noch spezifischer (erklären Sie also, wovon Sie abhängig sind). Daher würde ich nur eine Regel belassen: Wenn Ihre Direktive einen Status hat oder Daten aus dem Bereich benötigt, in dem sie verwendet wird, verwenden Sie einen isolierten Bereich. Verwenden Sie andernfalls keinen Bereich. Und über "Kinderbereiche" - ich habe auch ziemlich viele Anweisungen geschrieben und brauchte diese Funktion nie. Wenn "einige Elemente im übergeordneten Bereich geändert werden müssen", verwenden Sie Bindungen.$parent
Hack).ngRepeat
scope.$new();
scope: true
ngClick
usw.) Das Erfordernis erzeugt eine Art Entkopplung, der ich zustimme, aber Sie müssen immer noch die übergeordnete Richtlinie kennen. Wenn es nicht wie eine Komponente ist , bin ich gegen eine Isolation. Richtlinien (zumindest die meisten von ihnen) sollen in hohem Maße wiederverwendbar sein, und die Isolation bricht dies.Ich dachte nur, ich würde mein aktuelles Verständnis hinzufügen und wie es sich auf andere JS-Konzepte bezieht.
Standard (zB nicht deklariert oder Geltungsbereich: falsch)
Dies ist philosophisch gleichbedeutend mit der Verwendung globaler Variablen. Ihre Direktive kann auf alles im übergeordneten Controller zugreifen, wirkt sich jedoch auch auf diese aus und ist gleichzeitig betroffen.
Umfang:{}
Dies ist wie ein Modul. Alles, was es verwenden möchte, muss explizit übergeben werden. Wenn JEDE von Ihnen verwendete Direktive ein isolierter Bereich ist, kann dies der Erstellung JEDER JS-Datei entsprechen, für die Sie ein eigenes Modul schreiben, mit viel Aufwand beim Einfügen aller Abhängigkeiten.
Geltungsbereich: Kind
Dies ist der Mittelweg zwischen globalen Variablen und explizitem Passthrough. Es ähnelt der Prototypenkette von Javascript und erweitert lediglich eine Kopie des übergeordneten Bereichs. Wenn Sie einen isolierten Bereich erstellen und jedes Attribut und jede Funktion des übergeordneten Bereichs übergeben, entspricht dies funktional diesem.
Der Schlüssel ist, dass JEDE Direktive auf JEDE Weise geschrieben werden kann. Die verschiedenen Gültigkeitsbereichserklärungen dienen nur zur Organisation. Sie können alles zu einem Modul machen oder einfach alle globalen Variablen verwenden und sehr vorsichtig sein. Zur Erleichterung der Wartung ist es jedoch vorzuziehen, Ihre Logik in logisch zusammenhängende Teile zu modularisieren. Es besteht ein Gleichgewicht zwischen einer offenen Wiese und einem geschlossenen Gefängnis. Der Grund, warum dies schwierig ist, ist meiner Meinung nach, dass die Leute, wenn sie davon erfahren, denken, dass sie lernen, wie Direktiven funktionieren, aber tatsächlich lernen sie etwas über Code / Logik-Organisation.
Eine andere Sache, die mir geholfen hat herauszufinden, wie Direktiven funktionieren, ist das Erlernen von ngInclude. Mit ngInclude können Sie HTML-Partials einbinden. Als ich anfing, Direktiven zu verwenden, stellte ich fest, dass Sie die Vorlagenoption verwenden können, um Ihren Code zu reduzieren, aber ich habe keine Logik angehängt.
Natürlich musste ich zwischen den Anweisungen von Angular und der Arbeit des Angular-UI- Teams noch keine eigene Richtlinie erstellen, die etwas Wesentliches bewirkt, sodass meine Ansicht dazu möglicherweise völlig falsch ist.
quelle
Ich stimme Umur zu. Theoretisch klingen isolierte Bereiche wunderbar und "portabel", aber als ich meine App so erstellte, dass sie nicht triviale Funktionen beinhaltet, musste ich mehrere Anweisungen einfügen (einige in anderen verschachtelt oder Attribute hinzugefügt), um vollständig in meine zu schreiben eigenes HTML, das der Zweck einer domänenspezifischen Sprache ist.
Am Ende ist es zu seltsam, jeden globalen oder gemeinsam genutzten Wert in der Kette mit mehreren Attributen bei jedem DOM-Aufruf einer Direktive übergeben zu müssen (wie dies für den isolierten Bereich erforderlich ist). Es sieht einfach dumm aus, all das wiederholt in das DOM zu schreiben, und es fühlt sich ineffizient an, selbst wenn es sich um gemeinsam genutzte Objekte handelt. Dies erschwert auch die Richtlinienerklärungen unnötig. Die Problemumgehung bei der Verwendung von $ parent zum "Erreichen" und Abrufen von Werten aus der HTML-Direktive scheint eine sehr schlechte Form zu sein.
Auch ich habe meine App dahingehend geändert, dass sie hauptsächlich Anweisungen für den untergeordneten Bereich mit sehr wenigen Isolaten enthält - nur diejenigen, die vom übergeordneten Element auf nichts zugreifen müssen, außer auf das, was über einfache, sich nicht wiederholende Attribute weitergegeben werden kann.
Nachdem ich jahrzehntelang vom Traum von domänenspezifischen Sprachen geträumt habe, bevor es so etwas gab, bin ich hocherfreut, dass AngularJS diese Option bietet, und ich weiß, dass wir, wenn mehr Entwickler in diesem Bereich arbeiten, einige sehr coole Apps sehen werden, die sind auch für ihre Architekten einfach zu schreiben, zu erweitern und zu debuggen.
- D.
quelle