W przypadku, gdy masz wiele dyrektyw na jednym elemencie DOM i gdy kolejność, w jakiej są stosowane, ma znaczenie, możesz użyć priority
właściwości do zamówienia ich aplikacji. Wyższe liczby są uruchamiane jako pierwsze. Domyślny priorytet to 0, jeśli go nie określisz.
EDYCJA : po dyskusji, oto kompletne działające rozwiązanie. Kluczem było usunąć atrybut : element.removeAttr("common-things");
, a także element.removeAttr("data-common-things");
(w przypadku użytkowników określić data-common-things
w HTML)
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);
}
};
}
};
});
Działający plunker jest dostępny pod adresem : http://plnkr.co/edit/Q13bUt?p=preview
Lub:
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);
}
};
});
PRÓBNY
Wyjaśnienie, dlaczego musimy ustawić terminal: true
i priority: 1000
(dużą liczbę):
Gdy DOM jest gotowy, kątowy prowadzi DOM w celu zidentyfikowania wszystkich zarejestrowanych dyrektyw i kompilowania dyrektyw jeden po drugim w oparciu o to, priority
czy te dyrektywy dotyczą tego samego elementu . Możemy ustawić priorytet nasz zwyczaj dyrektywy do dużej liczby, aby zapewnić, że zostanie skompilowany pierwszy i terminal: true
, pozostałe dyrektywy zostaną pominięte po tej dyrektywy jest skompilowany.
Kiedy nasza niestandardowa dyrektywa zostanie skompilowana, zmodyfikuje element, dodając dyrektywy i usuwając się, i używa usługi $ compile do skompilowania wszystkich dyrektyw (w tym tych, które zostały pominięte) .
Jeśli nie ustawimy terminal:true
i priority: 1000
, istnieje szansa, że niektóre dyrektywy zostaną skompilowane przed naszą niestandardową dyrektywą. A kiedy nasza niestandardowa dyrektywa używa $ compile do skompilowania elementu => ponownie skompiluj już skompilowane dyrektywy. Spowoduje to nieprzewidziane zachowanie, szczególnie jeśli dyrektywy skompilowane przed naszą niestandardową dyrektywą już przekształciły DOM.
Aby uzyskać więcej informacji o priorytecie i terminalu, sprawdź Jak zrozumieć „terminal” dyrektywy?
Przykładem dyrektywy, która również modyfikuje szablon jest ng-repeat
(priorytet = 1000), kiedy ng-repeat
jest kompilowany, ng-repeat
wykonaj kopię elementu szablonu przed zastosowaniem innych dyrektyw .
Dzięki komentarzowi @ Izhaki tutaj znajduje się odniesienie do ngRepeat
kodu źródłowego: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js
RangeError: Maximum call stack size exceeded
kompilacja trwa wiecznie.element.removeAttr("common-datepicker");
aby uniknąć nieokreślonej pętli.replace: false
,terminal: true
,priority: 1000
; następnie ustaw pożądane atrybuty wcompile
funkcji i usuń nasz atrybut dyrektywy. Wreszcie wpost
funkcji zwróconej przezcompile
call$compile(element)(scope)
. Element będzie regularnie kompilowany bez niestandardowej dyrektywy, ale z dodanymi atrybutami. Starałem się nie usunąć niestandardowej dyrektywy i poradzić sobie z tym wszystkim w jednym procesie: wydaje się, że nie da się tego zrobić. Proszę odnieść się do zaktualizowanego plnkr: plnkr.co/edit/Q13bUt?p=preview .common-things
atrybutów można przekazać parametr maxPriority do polecenia kompilacji:$compile(element, null, 1000)(scope);
Możesz poradzić sobie z tym wszystkim za pomocą prostego znacznika szablonu. Zobacz http://jsfiddle.net/m4ve9/ dla przykładu. Zauważ, że tak naprawdę nie potrzebowałem właściwości kompilacji ani łącza w definicji super-dyrektywy.
Podczas procesu kompilacji, Angular pobiera wartości szablonu przed kompilacją, więc możesz dołączyć tam wszystkie dalsze dyrektywy, a Angular zajmie się tym za Ciebie.
Jeśli jest to super dyrektywa, która musi zachować oryginalną treść wewnętrzną, możesz użyć
transclude : true
i zastąpić wnętrze<ng-transclude></ng-transclude>
Mam nadzieję, że to pomoże, daj mi znać, jeśli coś jest niejasne
Alex
źródło
input
Tag, ale chciałbym, aby działał dla dowolnego elementu, takiego jakdiv
s lubselect
s.element
iattrs
przeszedł zajęło mi wieki, że z pracy, a ja nie widziałem go stosować wszędzie - ale wydaje się działać prawidłowo. stackoverflow.com/a/20137542/1455709Oto rozwiązanie, które przenosi dyrektywy, które należy dynamicznie dodawać, do widoku, a także dodaje opcjonalną (podstawową) logikę warunkową. To utrzymuje dyrektywę w czystości bez logiki na stałe.
Dyrektywa przyjmuje tablicę obiektów, każdy obiekt zawiera nazwę dyrektywy, która ma zostać dodana, i wartość, którą należy do niej przekazać (jeśli istnieje).
Próbowałem wymyślić przypadek użycia takiej dyrektywy, dopóki nie pomyślałem, że użyteczne może być dodanie logiki warunkowej, która dodaje tylko dyrektywę opartą na pewnych warunkach (choć odpowiedź poniżej jest nadal wymyślona). Dodałem opcjonalną
if
właściwość, która powinna zawierać wartość bool, wyrażenie lub funkcję (np. Zdefiniowaną w twoim kontrolerze), która określa, czy dyrektywa powinna zostać dodana czy nie.Używam również
attrs.$attr.dynamicDirectives
uzyskać deklarację atrybutu dokładnie używany dodać dyrektywy (npdata-dynamic-directive
,dynamic-directive
) bez twardych kodowania ciągów znaków w celu sprawdzenia.Plunker Demo
źródło
Chciałem dodać moje rozwiązanie, ponieważ zaakceptowane nie do końca działało.
Musiałem dodać dyrektywę, ale również utrzymywać mój na temat tego elementu.
W tym przykładzie dodałem prostą dyrektywę w stylu ng do elementu. Aby zapobiec nieskończonym pętlom kompilacji i pozwolić mi zachować moją dyrektywę, dodałem opcję sprawdzania, czy to, co dodałem, było obecne przed ponowną kompilacją elementu.
źródło
Spróbuj zapisać stan w atrybucie samego elementu, na przykład
superDirectiveStatus="true"
Na przykład:
Mam nadzieję, że to Ci pomoże.
źródło
Nastąpiła zmiana z 1.3.x na 1.4.x.
W Angular 1.3.x działało to:
Teraz w Angular 1.4.x musimy to zrobić:
(Z zaakceptowanej odpowiedzi: https://stackoverflow.com/a/19228302/605586 od Khanh TO).
źródło
Prostym rozwiązaniem, które może działać w niektórych przypadkach, jest utworzenie i $ skompilowanie opakowania, a następnie dołączenie do niego oryginalnego elementu.
Coś jak...
Zaletą tego rozwiązania jest to, że nie kompiluje oryginalnego elementu.
Nie działałoby to, jeśli którakolwiek z dyrektyw dodanych w
require
którejkolwiek z dyrektyw oryginalnego elementu lub jeśli element oryginalny ma bezwzględne pozycjonowanie.źródło