In Fällen, in denen Sie mehrere Anweisungen für ein einzelnes DOM-Element haben und die Reihenfolge, in der sie angewendet werden, von Bedeutung ist, können Sie die priority
Eigenschaft verwenden, um ihre Anwendung zu ordnen. Höhere Zahlen laufen zuerst. Die Standardpriorität ist 0, wenn Sie keine angeben.
EDIT : Nach der Diskussion ist hier die vollständige Arbeitslösung. Der Schlüssel bestand darin , das Attribut zu entfernen : element.removeAttr("common-things");
, und auch element.removeAttr("data-common-things");
(falls Benutzer data-common-things
im HTML angeben )
angular.module('app')
.directive('commonThings', function ($compile) {
return {
restrict: 'A',
replace: false,
terminal: true, //this setting is important, see explanation below
priority: 1000, //this setting is important, see explanation below
compile: function compile(element, attrs) {
element.attr('tooltip', '{{dt()}}');
element.attr('tooltip-placement', 'bottom');
element.removeAttr("common-things"); //remove the attribute to avoid indefinite loop
element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html
return {
pre: function preLink(scope, iElement, iAttrs, controller) { },
post: function postLink(scope, iElement, iAttrs, controller) {
$compile(iElement)(scope);
}
};
}
};
});
Der funktionierende Plunker ist verfügbar unter: http://plnkr.co/edit/Q13bUt?p=preview
Oder:
angular.module('app')
.directive('commonThings', function ($compile) {
return {
restrict: 'A',
replace: false,
terminal: true,
priority: 1000,
link: function link(scope,element, attrs) {
element.attr('tooltip', '{{dt()}}');
element.attr('tooltip-placement', 'bottom');
element.removeAttr("common-things"); //remove the attribute to avoid indefinite loop
element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html
$compile(element)(scope);
}
};
});
DEMO
Erklärung warum wir setzen müssen terminal: true
und priority: 1000
(eine hohe Zahl):
Wenn das DOM bereit ist, geht Angular durch das DOM, um alle registrierten Anweisungen zu identifizieren und die Anweisungen einzeln zu kompilieren, basierend darauf, priority
ob sich diese Anweisungen auf demselben Element befinden . Wir setzen unsere Priorität der benutzerdefinierten Richtlinie auf eine hohe Zahl , um sicherzustellen , dass es kompiliert werden erste und terminal: true
werden die anderen Richtlinien werden übersprungen , nachdem diese Richtlinie kompiliert wird.
Wenn unsere benutzerdefinierte Direktive kompiliert wird, ändert sie das Element, indem sie Direktiven hinzufügt und sich selbst entfernt, und verwendet den $ compile-Dienst, um alle Direktiven (einschließlich der übersprungenen) zu kompilieren .
Wenn wir das nicht tun gesetzt terminal:true
und priority: 1000
, gibt es eine Chance , dass einige Richtlinien zusammengestellt werden , bevor unsere eigene Richtlinie. Und wenn unsere benutzerdefinierte Direktive $ compile verwendet, um das Element zu kompilieren => kompilieren Sie die bereits kompilierten Direktiven erneut. Dies führt zu unvorhersehbarem Verhalten, insbesondere wenn die vor unserer benutzerdefinierten Anweisung kompilierten Anweisungen das DOM bereits transformiert haben.
Weitere Informationen zu Priorität und Terminal finden Sie unter Wie verstehe ich das Terminal der Richtlinie?
Ein Beispiel für eine Direktive, die auch die Vorlage ändert, ist ng-repeat
(Priorität = 1000). Wenn diese ng-repeat
kompiliert wird, ng-repeat
erstellen Sie Kopien des Vorlagenelements, bevor andere Direktiven angewendet werden .
Dank des Kommentars von @ Izhaki ist hier der Verweis auf den ngRepeat
Quellcode: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js
RangeError: Maximum call stack size exceeded
Es wird für immer kompiliert.element.removeAttr("common-datepicker");
, um eine unbestimmte Schleife zu vermeiden.replace: false
,terminal: true
,priority: 1000
; Stellen Sie dann die gewünschten Attribute in dercompile
Funktion ein und entfernen Sie unser Direktivenattribut. Rufen Sie schließlich in der von zurückgegebenenpost
Funktion auf . Das Element wird regelmäßig ohne die benutzerdefinierte Direktive, jedoch mit den hinzugefügten Attributen kompiliert. Was ich erreichen wollte, war, die benutzerdefinierte Direktive nicht zu entfernen und all dies in einem Prozess zu erledigen: Dies kann anscheinend nicht durchgeführt werden. Weitere Informationen finden Sie im aktualisierten plnkr: plnkr.co/edit/Q13bUt?p=preview .compile
$compile(element)(scope)
common-things
Attribute können Sie einen maxPriority-Parameter an den Kompilierungsbefehl übergeben:$compile(element, null, 1000)(scope);
All dies können Sie mit nur einem einfachen Vorlagen-Tag erledigen. Ein Beispiel finden Sie unter http://jsfiddle.net/m4ve9/ . Beachten Sie, dass ich für die Definition der Super-Direktive keine Kompilierungs- oder Verknüpfungseigenschaft benötigte.
Während des Kompilierungsprozesses zieht Angular vor dem Kompilieren die Vorlagenwerte ein, sodass Sie dort weitere Anweisungen anhängen können, und Angular kümmert sich für Sie darum.
Wenn dies eine Super-Direktive ist, die den ursprünglichen internen Inhalt beibehalten muss, können Sie
transclude : true
das Innere verwenden und durch ersetzen<ng-transclude></ng-transclude>
Hoffe das hilft, lass es mich wissen, wenn etwas unklar ist
Alex
quelle
input
Tag, aber ich möchte, dass es für jedes Element wiediv
s oderselect
s funktioniert .element
undattrs
übergeben. Ich habe ewigHier ist eine Lösung, die die Direktiven, die dynamisch hinzugefügt werden müssen, in die Ansicht verschiebt und außerdem eine optionale (grundlegende) bedingte Logik hinzufügt. Dies hält die Direktive ohne fest codierte Logik sauber.
Die Direktive enthält ein Array von Objekten. Jedes Objekt enthält den Namen der hinzuzufügenden Direktive und den Wert, der an sie übergeben werden soll (falls vorhanden).
Ich hatte Mühe, mir einen Anwendungsfall für eine solche Direktive vorzustellen, bis ich dachte, dass es nützlich sein könnte, eine bedingte Logik hinzuzufügen, die nur eine Direktive hinzufügt, die auf einer bestimmten Bedingung basiert (obwohl die folgende Antwort noch erfunden ist). Ich habe eine optionale
if
Eigenschaft hinzugefügt , die einen Bool-Wert, einen Ausdruck oder eine Funktion enthalten soll (z. B. in Ihrem Controller definiert), die bestimmt, ob die Direktive hinzugefügt werden soll oder nicht.Ich verwende auch
attrs.$attr.dynamicDirectives
die genaue Attribut - Deklaration erhalten verwendet , um die Richtlinie hinzuzufügen (zBdata-dynamic-directive
,dynamic-directive
) ohne Werte hart codierte Zeichenfolge zu überprüfen.Plunker Demo
quelle
Ich wollte meine Lösung hinzufügen, da die akzeptierte für mich nicht ganz funktionierte.
Ich musste eine Direktive hinzufügen, aber auch meine auf dem Element behalten.
In diesem Beispiel füge ich dem Element eine einfache Direktive im ng-Stil hinzu. Um unendliche Kompilierungsschleifen zu vermeiden und meine Direktive beizubehalten, habe ich vor dem erneuten Kompilieren des Elements überprüft, ob das, was ich hinzugefügt habe, vorhanden war.
quelle
Versuchen Sie, den Status in einem Attribut für das Element selbst zu speichern, z
superDirectiveStatus="true"
Beispielsweise:
Ich hoffe das hilft dir.
quelle
Es gab eine Änderung von 1.3.x zu 1.4.x.
In Angular 1.3.x funktionierte dies:
In Angular 1.4.x müssen wir Folgendes tun:
(Aus der akzeptierten Antwort: https://stackoverflow.com/a/19228302/605586 von Khanh TO).
quelle
Eine einfache Lösung, die in einigen Fällen funktionieren könnte, besteht darin, einen Wrapper zu erstellen und zu kompilieren und dann Ihr ursprüngliches Element daran anzuhängen.
Etwas wie...
Diese Lösung hat den Vorteil, dass sie die Dinge einfach hält, indem das ursprüngliche Element nicht neu kompiliert wird.
Dies würde nicht funktionieren, wenn eine der hinzugefügten Anweisungen
require
eine der Anweisungen des ursprünglichen Elements ist oder wenn das ursprüngliche Element eine absolute Positionierung hat.quelle