В тех случаях, когда у вас есть несколько директив для одного элемента DOM, и когда порядок, в котором они применяются, имеет значение, вы можете использовать это priority
свойство для заказа их приложения. Более высокие числа запускаются первыми. Приоритет по умолчанию - 0, если вы его не указали.
РЕДАКТИРОВАТЬ : после обсуждения, вот полное рабочее решение. Ключ должен был удалить атрибут :, element.removeAttr("common-things");
а также element.removeAttr("data-common-things");
(в случае, если пользователи указывают data-common-things
в 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);
}
};
}
};
});
Работающий плункер доступен по адресу: http://plnkr.co/edit/Q13bUt?p=preview
Или:
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
Объяснение, почему мы должны установить terminal: true
и priority: 1000
(большое число):
Когда DOM готов, angular обходит DOM, чтобы идентифицировать все зарегистрированные директивы и компилировать директивы одну за другой, основываясь на priority
том, находятся ли эти директивы в одном и том же элементе . Мы устанавливаем приоритет нашей пользовательской директивы на большое число, чтобы гарантировать, что она будет скомпилирована первой, а terminal: true
другие директивы будут пропущены после компиляции этой директивы.
Когда наша пользовательская директива компилируется, она изменяет элемент, добавляя директивы и удаляя себя, и использует $ compile service для компиляции всех директив (включая те, которые были пропущены) .
Если мы не установим terminal:true
и priority: 1000
, есть вероятность, что некоторые директивы скомпилированы перед нашей пользовательской директивой. И когда наша пользовательская директива использует $ compile для компиляции element => compile снова уже скомпилированные директивы. Это приведет к непредсказуемому поведению, особенно если директивы, скомпилированные до нашей пользовательской директивы, уже преобразовали DOM.
Для получения дополнительной информации о приоритете и терминале, посмотрите Как понять `терминал` директивы?
Примером директивы, которая также изменяет шаблон, является ng-repeat
(приоритет = 1000), когда ng-repeat
он скомпилирован, ng-repeat
создайте копии элемента шаблона перед применением других директив .
Благодаря комментарию @ Izhaki, вот ссылка на ngRepeat
исходный код: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js
RangeError: Maximum call stack size exceeded
как он вечно компилируется.element.removeAttr("common-datepicker");
чтобы избежать неопределенного цикла.replace: false
,terminal: true
,priority: 1000
; затем установите желаемые атрибуты вcompile
функции и удалите наш атрибут директивы. Наконец, вpost
функции, возвращаемой функциейcompile
call$compile(element)(scope)
. Элемент будет регулярно компилироваться без специальной директивы, но с добавленными атрибутами. То, чего я пытался добиться, - это не удалять пользовательскую директиву и обрабатывать все это в одном процессе: кажется, этого нельзя сделать. Пожалуйста, обратитесь к обновленному plnkr: plnkr.co/edit/Q13bUt?p=preview .common-things
атрибутов вы можете передать параметр maxPriority в команду компиляции:$compile(element, null, 1000)(scope);
Вы можете справиться со всем этим с помощью простого тега шаблона. См. Http://jsfiddle.net/m4ve9/ для примера. Обратите внимание, что на самом деле мне не нужно свойство compile или link в определении супер-директивы.
В процессе компиляции Angular извлекает значения шаблона перед компиляцией, поэтому вы можете прикрепить туда любые дополнительные директивы, и Angular позаботится об этом за вас.
Если это супер-директива, которая должна сохранить исходный внутренний контент, вы можете использовать
transclude : true
и заменить внутри<ng-transclude></ng-transclude>
Надеюсь, это поможет, дайте мне знать, если что-то неясно
Alex
источник
input
Тег, но я бы хотел, чтобы он работал для любого элемента, такого какdiv
s илиselect
s.element
иattrs
передать ее. Мне понадобились целые годы, чтобы понять это, и я не видел, чтобы он где-либо использовался - но, кажется, работает нормально: stackoverflow.com/a/20137542/1455709Вот решение, которое перемещает директивы, которые должны быть добавлены динамически, в представление, а также добавляет некоторую необязательную (базовую) условную логику. Это поддерживает директиву в чистоте без жестко закодированной логики.
Директива принимает массив объектов, каждый объект содержит имя добавляемой директивы и значение для передачи ей (если есть).
Я изо всех сил пытался придумать вариант использования такой директивы, пока не подумал, что было бы полезно добавить некоторую условную логику, которая добавляет директиву только на основе некоторого условия (хотя ответ ниже все еще надуман). Я добавил необязательное
if
свойство, которое должно содержать значение bool, выражение или функцию (например, определенную в вашем контроллере), которая определяет, следует ли добавлять директиву или нет.Я также использую,
attrs.$attr.dynamicDirectives
чтобы получить точное объявление атрибута, используемое для добавления директивы (напримерdata-dynamic-directive
,dynamic-directive
) без жестко заданных значений строк для проверки.Plunker Demo
источник
Я хотел добавить свое решение, так как принятый вариант мне не помог.
Мне нужно было добавить директиву, но также и мою.
В этом примере я добавляю простую директиву в стиле ng к элементу. Чтобы предотвратить бесконечные циклы компиляции и позволить мне сохранить мою директиву, я добавил проверку, чтобы увидеть, присутствовало ли то, что я добавил, перед перекомпиляцией элемента.
источник
Попробуйте сохранить состояние в атрибуте самого элемента, например
superDirectiveStatus="true"
Например:
Я надеюсь, это поможет вам.
источник
Произошло изменение с 1.3.x до 1.4.x.
В Angular 1.3.x это сработало:
Теперь в Angular 1.4.x мы должны сделать это:
(Из принятого ответа: https://stackoverflow.com/a/19228302/605586 от Khanh TO).
источник
Простое решение, которое может работать в некоторых случаях, - это создать и $ compile обертку, а затем добавить к ней исходный элемент.
Что-то вроде...
Преимущество этого решения в том, что оно упрощает задачу, не перекомпилируя исходный элемент.
Это не будет работать, если какая-либо из добавленных директив является
require
любой из директив исходного элемента или если исходный элемент имеет абсолютное позиционирование.источник