Улучшить эту документацию Посмотреть исходный код $compile
- $compileProvider
- сервис в модуле ng
Обзор
Компилирует строку HTML или DOM в шаблон и создает функцию шаблона, которая затем может использоваться для связывания scope и шаблона.
Компиляция — это процесс обхода дерева DOM и сопоставления элементов DOM с директивами.
Полный API директивы
Существует множество различных вариантов директивы.
Разница заключается в возвращаемом значении функции-фабрики. Вы можете вернуть объект определения директивы (см. ниже), который определяет свойства директивы, или просто функцию postLink (все остальные свойства будут иметь значения по умолчанию).
Вот пример директивы, объявленной с объектом определения директивы:
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
priority: 0,
template: '<div></div>', // or // function(tElement, tAttrs) { ... },
// or
// templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
transclude: false,
restrict: 'A',
templateNamespace: 'html',
scope: false,
controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
controllerAs: 'stringIdentifier',
bindToController: false,
require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
multiElement: false,
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
post: function postLink(scope, iElement, iAttrs, controller) { ... }
}
// or
// return function postLink( ... ) { ... }
},
// or
// link: {
// pre: function preLink(scope, iElement, iAttrs, controller) { ... },
// post: function postLink(scope, iElement, iAttrs, controller) { ... }
// }
// or
// link: function postLink( ... ) { ... }
};
return directiveDefinitionObject;
});
Поэтому вышеуказанное можно упростить:
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
link: function postLink(scope, iElement, iAttrs) { ... }
};
return directiveDefinitionObject;
// or
// return function postLink(scope, iElement, iAttrs) { ... }
});
Обработчики жизненного цикла
Контроллеры директивы могут предоставлять следующие методы, которые вызываются AngularJS в определенные моменты жизненного цикла директивы:
-
$onInit()— Вызывается для каждого контроллера после создания всех контроллеров на элементе и инициализации их привязок (и перед функциями предварительной и последующей привязки для директивы на этом элементе). Это хорошее место для размещения кода инициализации контроллера. -
$onChanges(changesObj)— Вызывается всякий раз, когда обновляются односторонние (<) или интерполяционные (@) привязки.changesObj— это хеш, ключами которого являются имена связанных свойств, которые изменились, а значениями — объект вида{ currentValue, previousValue, isFirstChange() }. Используйте этот обработчик для запуска обновлений внутри компонента, например, для клонирования связанного значения, чтобы предотвратить случайное изменение внешнего значения. Обратите внимание, что это также будет вызвано при инициализации ваших привязок. -
$doCheck()— Вызывается на каждом шаге цикла переваривания. Предлагает возможность обнаруживать и реагировать на изменения. Любые действия, которые вы хотите выполнить в ответ на обнаруженные изменения, должны быть вызваны из этого обработчика; реализация этого не влияет на время вызова$onChanges. Например, этот обработчик может быть полезен, если вы хотите выполнить проверку глубокого равенства или проверить объект Date, изменения в котором не будут обнаружены детектором изменений AngularJS и, следовательно, не вызовут$onChanges. Этот обработчик вызывается без аргументов; при обнаружении изменений вы должны сохранить предыдущее(ые) значение(я) для сравнения с текущими значениями. -
$onDestroy()— Вызывается для контроллера, когда содержащий его scope уничтожается. Используйте этот обработчик для освобождения внешних ресурсов, наблюдений и обработчиков событий. Обратите внимание, что обработчики$onDestroy()компонентов вызываются в том же порядке, что и события$scope.$broadcast, что происходит сверху вниз. Это означает, что обработчик$onDestroy()родительских компонентов будет вызван до дочерних компонентов. -
$postLink()— Вызывается после привязки элемента этого контроллера и его дочерних элементов. Подобно функции пост-привязки, этот обработчик может использоваться для настройки обработчиков событий DOM и выполнения непосредственной манипуляции с DOM. Обратите внимание, что дочерние элементы, содержащие директивыtemplateUrl, не будут скомпилированы и связаны, поскольку они ожидают загрузки своего шаблона асинхронно, и их собственная компиляция и привязка приостановлены до тех пор, пока это не произойдет.
Сравнение с обработчиками жизненного цикла в новом Angular
Новый Angular также использует обработчики жизненного цикла для своих компонентов. Хотя обработчики жизненного цикла AngularJS похожи, есть некоторые отличия, о которых вам следует знать, особенно при переносе кода из AngularJS в Angular:
- Обработчики AngularJS имеют префикс
$, например,$onInit. Обработчики Angular имеют префиксng, например,ngOnInit. - Обработчики AngularJS могут быть определены в прототипе контроллера или добавлены в контроллер внутри его конструктора. В Angular вы можете определять обработчики только в прототипе класса компонента.
- Из-за различий в обнаружении изменений вы можете получить гораздо больше вызовов
$doCheckв AngularJS, чемngDoCheckв Angular. - Изменения модели внутри
$doCheckвызовут новые циклы переваривания, что приведет к распространению изменений по всему приложению. Angular не позволяет обработчикуngDoCheckвызывать изменения за пределами компонента. Он либо выдаст ошибку, либо ничего не сделает в зависимости от состоянияenableProdMode().
Примеры обработчиков жизненного цикла
Этот пример показывает, как можно проверить изменения объекта Date, даже если идентичность объекта не изменилась.
Этот пример показывает, как вы можете использовать $doCheck для запуска изменений вводах вашего компонента, даже если фактическая идентичность компонента не меняется. (Обратите внимание, что клонирование и проверки глубокого равенства для больших массивов или объектов могут негативно сказаться на производительности вашего приложения)
Объект определения директивы
Объект определения директивы предоставляет инструкции для компилятора. Атрибуты:
multiElement
Когда это свойство установлено в true (значение по умолчанию — false), HTML-компилятор соберет узлы DOM между узлами с атрибутами directive-name-start и directive-name-end и сгруппирует их вместе как элементы директивы. Рекомендуется использовать эту функцию для директивы, которая не является строго поведенческой (например, ngClick) и не манипулирует и не заменяет дочерние узлы (например, ngInclude).
priority
Когда для одного элемента DOM определено несколько директив, иногда необходимо указать порядок применения директив. priority используется для сортировки директив перед вызовом их функций compile. Приоритет определяется как число. Директивы с большим числовым priority компилируются первыми. Функции предварительной привязки также выполняются в порядке приоритета, но функции последующей привязки выполняются в обратном порядке. Порядок директив с одинаковым приоритетом не определен. Значение по умолчанию для приоритета — 0.
terminal
Если установлено в true, то текущий priority будет последним набором директив, которые будут выполнены (любые директивы на текущем приоритете все равно будут выполнены, так как порядок выполнения на том же priority не определен). Обратите внимание, что выражения и другие директивы, используемые в шаблоне директивы, также будут исключены из выполнения.
scope
Свойство scope может быть false, true или объектом:
-
false(по умолчанию): Для директивы не будет создан scope. Директива будет использовать scope своего родителя. -
true: Для элемента директивы будет создан новый дочерний scope, который прототипически наследует от своего родителя. Если несколько директив на одном элементе запрашивают новый scope, создается только один новый scope. -
{...}(объект хеш): Для шаблона директивы создается новый изолированный scope. Изолированный scope отличается от обычного scope тем, что он не прототипически наследует от своего родительского scope. Это полезно при создании повторно используемых компонентов, которые не должны случайно считывать или изменять данные в родительском scope. Обратите внимание, что директива изолированного scope безtemplateилиtemplateUrlне применит изолированный scope к своим дочерним элементам.
Объект хеш изолированного scope определяет набор локальных свойств scope, полученных из атрибутов на элементе директивы. Эти локальные свойства полезны для алиасирования значений для шаблонов. Ключи в объекте хеш отображаются в имя свойства в изолированном scope; значения определяют, как свойство связано с родительским scope, посредством сопоставления атрибутов на элементе директивы:
-
@или@attr— привязывает свойство локальной области видимости к значению атрибута DOM. Результат всегда является строкой, так как атрибуты DOM являются строками. Если имяattrне указано, то имя атрибута предполагается таким же, как локальное имя. Учитывая<my-component my-attr="hello {{name}}">и определение области видимости изоляцииscope: { localName:'@myAttr' }, свойство области видимости директивыlocalNameбудет отражать интерполированное значениеhello {{name}}. По мере изменения атрибутаnameбудет меняться и свойствоlocalNameв области видимости директивы. Значениеnameсчитывается из родительской области видимости (не из области видимости директивы). -
=или=attr— устанавливает двунаправленную привязку между свойством локальной области видимости и выражением, переданным через атрибутattr. Выражение оценивается в контексте родительской области видимости. Если имяattrне указано, то имя атрибута предполагается таким же, как локальное имя. Учитывая<my-component my-attr="parentModel">и определение области видимости изоляцииscope: { localModel: '=myAttr' }, свойствоlocalModelв области видимости директивы будет отражать значениеparentModelв родительской области видимости. Изменения вparentModelбудут отражены вlocalModelи наоборот. Если выражение привязки не присваиваемое, или если атрибут не является необязательным и не существует, при обнаружении изменений в локальном значении будет выброшено исключение ($compile:nonassign), так как будет невозможно синхронизировать их обратно в родительскую область видимости.По умолчанию используется метод
$watchдля отслеживания изменений, и проверка на равенство основана на тождественности объекта. Однако, если в качестве выражения привязки передано литерал объекта или массив, проверка на равенство выполняется по значению (используя функциюangular.equals). Также возможно отслеживать оцененное значение поверхностно с помощью$watchCollection: используйте=*или=*attr -
<или<attr— устанавливает одностороннюю привязку между свойством локальной области видимости и выражением, переданным через атрибутattr. Выражение оценивается в контексте родительской области видимости. Если имяattrне указано, то имя атрибута предполагается таким же, как локальное имя.Например, при
<my-component my-attr="parentModel">и определении директивыscope: { localModel:'<myAttr' }, свойство изолированной области видимостиlocalModelбудет отражать значениеparentModelв родительской области видимости. Любые изменения вparentModelбудут отражены вlocalModel, но изменения вlocalModelне будут отражены вparentModel. Однако есть два нюанса:- односторонняя привязка не копирует значение из родительской области видимости в область видимости изоляции, она просто устанавливает то же значение. Это означает, что если привязанное значение является объектом, изменения его свойств в изолированной области видимости будут отражены в родительской области видимости (потому что оба ссылаются на один и тот же объект).
- односторонняя привязка отслеживает изменения тождества родительского значения. Это означает, что
$watchна родительском значении срабатывает только если ссылка на значение изменилась. В большинстве случаев об этом не стоит беспокоиться, но это может быть важно, если вы привязываете односторонне к объекту, а затем заменяете этот объект в изолированной области видимости. Если теперь вы изменяете свойство объекта в родительской области видимости, изменение не будет распространено в изолированную область видимости, потому что тождество объекта в родительской области видимости не изменилось. Вместо этого вы должны присвоить новый объект.
Односторонняя привязка полезна, если вы не планируете распространять изменения в привязках вашей изолированной области видимости обратно в родительскую. Однако это не делает это полностью невозможным.
По умолчанию используется метод
$watchдля отслеживания изменений, и проверка на равенство основана на тождественности объекта. Также возможно отслеживать оцененное значение поверхностно с помощью$watchCollection: используйте<*или<*attr -
&или&attr— предоставляет способ выполнения выражения в контексте родительской области видимости. Если имяattrне указано, то имя атрибута предполагается таким же, как локальное имя. Учитывая<my-component my-attr="count = count + value">и определение области видимости изоляцииscope: { localFn:'&myAttr' }, свойство изолированной области видимостиlocalFnбудет указывать на функцию-обёртку для выраженияcount = count + value. Часто желательно передавать данные из изолированной области видимости через выражение в родительскую область видимости. Это можно сделать, передав карту имён локальных переменных и их значений в функцию-обёртку fn. Например, если выражение —increment(amount), то мы можем указать значение amount, вызвавlocalFnкакlocalFn({amount: 22}).
Все 4 вида привязок (@, =, < и &) могут быть сделаны необязательными, добавив ? к выражению. Маркер должен стоять после режима и перед именем атрибута. См. ошибку неверного определения изолированной области видимости для примеров определения. Это полезно для уточнения интерфейса, предоставляемого директивами. Существует небольшое различие между необязательными и обязательными привязками, когда атрибут привязки не установлен:
- привязка необязательная: свойство не будет определено
- привязка обязательная: свойство определено
app.directive('testDir', function() {
return {
scope: {
notoptional: '=',
optional: '=?',
},
bindToController: true,
controller: function() {
this.$onInit = function() {
console.log(this.hasOwnProperty('notoptional')) // true
console.log(this.hasOwnProperty('optional')) // false
}
}
}
})
Комбинирование директив с различными определениями области видимости
В целом можно применять более одной директивы к одному элементу, но могут быть ограничения в зависимости от типа области видимости, требуемой директивами. Следующие пункты помогут объяснить эти ограничения. Для простоты учитываются только две директивы, но это также применимо к нескольким директивам:
- без области видимости + без области видимости => Две директивы, не требующие своей области видимости, будут использовать область видимости родителя
- дочерняя область видимости + без области видимости => Обе директивы будут использовать одну общую дочернюю область видимости
- дочерняя область видимости + дочерняя область видимости => Обе директивы будут использовать одну общую дочернюю область видимости
- изолированная область видимости + без области видимости => Директива с изолированной областью видимости будет использовать созданную изолированную область видимости. Другая директива будет использовать область видимости родителя
- изолированная область видимости + дочерняя область видимости => Не сработает! Только одна область видимости может быть связана с одним элементом. Поэтому эти директивы не могут быть применены к одному и тому же элементу.
- изолированная область видимости + изолированная область видимости => Не сработает! Только одна область видимости может быть связана с одним элементом. Поэтому эти директивы не могут быть применены к одному и тому же элементу.
bindToController
Это свойство используется для привязки свойств области видимости непосредственно к контроллеру. Оно может быть либо true, либо хэшем объекта с тем же форматом, что и свойство scope.
Когда для директивы используется изолированная область видимости (см. выше), bindToController: true позволит компоненту привязать свои свойства к контроллеру, а не к области видимости.
После создания контроллера начальные значения привязок изолированной области видимости будут привязаны к свойствам контроллера. Вы можете получить доступ к этим привязкам после их инициализации, предоставив метод контроллера, называемый $onInit, который вызывается после того, как все контроллеры элемента были построены и инициализированы их привязки.
Также возможно установить bindToController в хэш объекта с тем же форматом, что и свойство scope. Это установит привязки области видимости к контроллеру напрямую. Обратите внимание, что scope по-прежнему можно использовать для определения типа создаваемой области видимости. По умолчанию область видимости не создаётся. Используйте scope: {} для создания изолированной области видимости (полезно для компонентных директив).
Если оба bindToController и scope определены и имеют хэши объектов, то bindToController переопределяет scope.
controller
Конструктор функции контроллера. Контроллер создаётся до фазы предварительной привязки и может быть получен другими директивами (см. атрибут require). Это позволяет директивам взаимодействовать друг с другом и дополнять друг друга. Контроллер инжектируем (и поддерживает квадратные скобки) со следующими локалями:
-
$scope— текущая область видимости, связанная с элементом -
$element— текущий элемент -
$attrs— текущий объект атрибутов для элемента -
$transclude— функция привязки трансляции, предварительно привязанная к правильной области видимости трансляции:function([scope], cloneLinkingFn, futureParentElement, slotName):-
scope: (необязательно) переопределить область видимости. -
cloneLinkingFn: (необязательно) аргумент для создания клонов исходного транслированного содержимого. -
futureParentElement(необязательно):- определяет родителя, к которому
cloneLinkingFnдобавит клонированные элементы. - по умолчанию:
$element.parent()соответственно$elementдляtransclude:'element'соответственноtransclude:true. - необходимо только для трансляций, которые могут содержать не html элементы (например, SVG элементы) и когда передаётся
cloneLinkingFn, так как эти элементы нужно создать и клонировать особым образом, когда они определены вне своих обычных контейнеров (например, как<svg>). - См. также свойство
directive.templateNamespace.
- определяет родителя, к которому
-
slotName: (необязательно) имя слота для трансляции. Если ложно (например,null,undefinedили''), то предоставляется стандартная трансляция. Функция$transcludeтакже имеет метод на ней,$transclude.isSlotFilled(slotName), который возвращаетtrue, если указанный слот содержит содержимое (т.е. один или несколько узлов DOM).
-
require
Требует другую директиву и вводит её контроллер как четвёртый аргумент функции привязки. Свойство require может быть строкой, массивом или объектом:
- a строка содержащая имя директивы, передаваемой в функцию связывания
- a массив содержащий имена директив, передаваемых в функцию связывания. Аргументом, передаваемым в функцию связывания, будет массив контроллеров в том же порядке, что и имена в свойстве
require - an объект, значения свойств которого являются именами директив, передаваемых в функцию связывания. Аргументом, передаваемым в функцию связывания, также будет объект с соответствующими ключами, значения которых будут содержать соответствующие контроллеры.
Если свойство require является объектом и bindToController имеет истинное значение, то требуемые контроллеры привязываются к контроллеру, используя ключи свойства require. Эта привязка происходит после того, как все контроллеры были построены, но до вызова $onInit. Если имя требуемого контроллера совпадает с локальным именем (ключом), имя можно опустить. Например, {parentDir: '^^'} эквивалентно {parentDir: '^^parentDir'}. См. $compileProvider для примера использования.
- (без префикса) - найти требуемый контроллер в текущем элементе. Выбросить ошибку, если не найдено.
-
?- Попытаться найти требуемый контроллер или передатьnullфункцииlink, если не найдено. -
^- Найти требуемый контроллер, выполнив поиск в элементе и его родителях. Выбросить ошибку, если не найдено. -
^^- Найти требуемый контроллер, выполнив поиск в родителях элемента. Выбросить ошибку, если не найдено. -
?^- Попытаться найти требуемый контроллер, выполнив поиск в элементе и его родителях или передатьnullфункцииlink, если не найдено. -
?^^- Попытаться найти требуемый контроллер, выполнив поиск в родителях элемента, или передатьnullфункцииlink, если не найдено.
controllerAs
Имя идентификатора для ссылки на контроллер в области видимости директивы. Это позволяет ссылаться на контроллер из шаблона директивы. Это особенно полезно, когда директива используется в качестве компонента, т.е. со областью видимости isolate. Также можно использовать ее в директиве без области видимости isolate / new, но нужно понимать, что ссылка controllerAs может перезаписать свойство, которое уже существует в родительской области видимости.
restrict
Строка или подмножество EACM, которые ограничивают директиву определенным стилем объявления директивы. Если опущено, используются значения по умолчанию (элементы и атрибуты).
-
E- Имя элемента (значение по умолчанию):<my-directive></my-directive> -
A- Атрибут (значение по умолчанию):<div my-directive="exp"></div> -
C- Класс:<div class="my-directive: exp;"></div> -
M- Комментарий:<!-- directive: my-directive exp -->
templateNamespace
Строка, представляющая тип документа, используемый разметкой в шаблоне. AngularJS нуждается в этой информации, так как этим элементам необходимо создавать и клонировать особым образом, когда они определены вне своих обычных контейнеров, таких как <svg> и <math>.
-
html- Все корневые узлы в шаблоне являются HTML. Корневые узлы также могут быть верхнеуровневыми элементами, такими как<svg>или<math>. -
svg- Корневые узлы в шаблоне являются элементами SVG (исключая<math>). -
math- Корневые узлы в шаблоне являются элементами MathML (исключая<svg>).
Если templateNamespace не указан, то пространство имен считается html.
template
HTML-разметка, которая может:
- Заменить содержимое элемента директивы (значение по умолчанию).
- Заменить сам элемент директивы (если
replaceимеет значение true - УСТАРЕВШЕЕ). - Обернуть содержимое элемента директивы (если
transcludeимеет значение true).
Значение может быть:
- Строкой. Например,
<div red-on-hover>{{delete_str}}</div>. - Функцией, которая принимает два аргумента
tElementиtAttrs(описаны в API-функцииcompile) и возвращает строковое значение.
templateUrl
Это аналогично template, но шаблон загружается с указанного URL-адреса асинхронно.
Поскольку загрузка шаблона асинхронная, компилятор приостановит компиляцию директив в этом элементе до тех пор, пока шаблон не будет разрешен. Тем временем он продолжит компиляцию и связывание соседних и родительских элементов так, как будто этот элемент не содержал никаких директив.
Компилятор не приостанавливает всю компиляцию, чтобы дождаться загрузки шаблонов асинхронно, так как это приведет к "зависанию" всего приложения до тех пор, пока все шаблоны не будут загружены асинхронно – даже в том случае, когда у одной глубоко вложенной директивы есть templateUrl.
Загрузка шаблона является асинхронной, даже если шаблон был предварительно загружен в $templateCache
Вы можете указать templateUrl как строку, представляющую URL-адрес, или как функцию, которая принимает два аргумента tElement и tAttrs (описаны в API-функции compile) и возвращает строковое значение, представляющее URL-адрес. В любом случае URL-адрес шаблона проходит через $sce.getTrustedResourceUrl.
replace
replace устарело в AngularJS и было удалено в новом Angular (v2+). Указывает, что должен заменить шаблон. По умолчанию используется false.
-
true- шаблон заменит элемент директивы. -
false- шаблон заменит содержимое элемента директивы.
Процесс замены мигрирует все атрибуты/классы из старого элемента в новый. См. Руководство по директивам для примера.
Существует очень мало сценариев, где требуется замена элемента для работы приложения, основным из которых являются повторно используемые пользовательские компоненты, которые используются в контекстах SVG (потому что SVG не работает с пользовательскими элементами в дереве DOM).
transclude
Извлечь содержимое элемента, где появляется директива, и сделать его доступным для директивы. Содержимое компилируется и предоставляется директиве в виде функции трансклюзии. См. раздел Трансклюзия ниже.
compile
function compile(tElement, tAttrs, transclude) { ... }
Функция компиляции обрабатывает преобразование шаблона DOM. Поскольку большинство директив не выполняют преобразования шаблона, она используется нечасто. Функция компиляции принимает следующие аргументы:
-
tElement- элемент шаблона - Элемент, где была объявлена директива. Можно безопасно выполнять преобразования шаблона только на элементе и его дочерних элементах. -
tAttrs- атрибуты шаблона - Нормализованный список атрибутов, объявленных в этом элементе, общий для всех функций компиляции директив. -
transclude- [УСТАРЕЛО!] Функция связывания трансклюзии:function(scope, cloneLinkingFn)
template или templateUrl объявления, или ручную компиляцию внутри функции компиляции.transclude, которая передаётся функции компиляции, устарела, поскольку, например, она не знает о правильной внешней области видимости. Пожалуйста, используйте функцию трансклюзии, которая передаётся функции связывания вместо неё.Функция компиляции может иметь возвращаемое значение, которое может быть функцией или объектом.
-
возвращение функции (после связывания) - эквивалентно регистрации функции связывания через свойство
linkобъекта конфигурации, когда функция компиляции пуста. -
возвращение объекта с зарегистрированной(ими) функцией(ями) через свойства
preиpost- позволяет управлять временем вызова функции связывания во время фазы связывания. См. информацию о функциях до связывания и после связывания ниже.
link
Это свойство используется только в том случае, если свойство compile не определено.
function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
Функция связывания отвечает за регистрацию слушателей DOM и обновление DOM. Она выполняется после того, как шаблон был скопирован. Именно здесь будет размещена большая часть логики директивы.
-
scope- Область видимости - Область видимости, используемая директивой для регистрации наблюдателей. -
iElement- элемент экземпляра - Элемент, в котором должна использоваться директива. Изменять потомков элемента безопасно только в функцииpostLink, так как потомки уже связаны. -
iAttrs- атрибуты экземпляра - Нормализованный список атрибутов, объявленных в этом элементе, общий для всех функций связывания директивы. -
controller- экземпляр(ы) требуемого контроллера директивы - Экземпляры разделяются между всеми директивами, что позволяет директивам использовать контроллеры как канал связи. Точное значение зависит от свойстваrequireдирективы:- нет требуемого контроллера(ов): собственный контроллер директивы или
undefined, если его нет -
string: экземпляр контроллера -
array: массив экземпляров контроллеров
Если требуемый контроллер не найден, а он необязателен, экземпляр
null, в противном случае выбрасывается ошибка Отсутствующий требуемый контроллер.Обратите внимание, что вы также можете потребовать собственный контроллер директивы - он будет доступен как любой другой контроллер.
- нет требуемого контроллера(ов): собственный контроллер директивы или
-
transcludeFn- функция связывания транклюзии, предварительно связанная с правильной областью видимости транклюзии. Это то же самое, что и параметр$transcludeконтроллеров директив, см. раздел контроллера для получения подробностей.function([scope], cloneLinkingFn, futureParentElement).
Функция предварительного связывания
Выполняется перед связыванием дочерних элементов. Небезопасно выполнять преобразования DOM, так как функция связывания компилятора не сможет найти правильные элементы для связывания.
Функция пост-связывания
Выполняется после связывания дочерних элементов.
Обратите внимание, что дочерние элементы, содержащие templateUrl директивы, не будут скомпилированы и связаны, поскольку они ожидают загрузки своего шаблона асинхронно, а их собственная компиляция и связывание приостановлены до тех пор, пока это не произойдёт.
Безопасно выполнять преобразования DOM в функции пост-связывания для элементов, которые не ожидают разрешения своих асинхронных шаблонов.
Транклюзия
Транклюзия — это процесс извлечения набора элементов DOM из одной части DOM и копирования их в другую часть DOM, сохраняя при этом их связь с исходной областью видимости AngularJS, из которой они были взяты.
Транклюзия используется (часто с ngTransclude) для вставки исходного содержимого элемента директивы в указанное место в шаблоне директивы. Преимущество транклюзии по сравнению с ручным перемещением элементов DOM заключается в том, что содержимое транклюзии имеет доступ к свойствам в области видимости, из которой оно было взято, даже если у директивы изолированная область видимости. См. Руководство по директивам.
Это позволяет виджету иметь частное состояние для своего шаблона, в то время как содержимое транклюзии имеет доступ к своей исходной области видимости.
Существует три вида транклюзии, в зависимости от того, хотите ли вы транклюдировать только содержимое элемента директивы, весь элемент или несколько частей содержимого элемента:
-
true- транклюдировать содержимое (то есть дочерние узлы) элемента директивы. -
'element'- транклюдировать весь элемент директивы, включая любые директивы в этом элементе, определённые с более низким приоритетом, чем эта директива. При использовании свойствоtemplateигнорируется. -
{...}(хеш объекта): - сопоставлять элементы содержимого с "слотами" транклюзии в шаблоне.
Транклюзия с несколькими слотами объявляется путём предоставления объекта для свойства transclude.
Этот объект — это карта, где ключи — это имя слота для заполнения, а значения — селектор элемента, используемый для сопоставления HTML со слотом. Селектор элемента должен быть в нормализованной форме (например, myElement) и будет соответствовать стандартным вариантам элементов (например, my-element, my:element, data-my-element и т. д.).
Для получения дополнительной информации ознакомьтесь с руководством по Сопоставлению директив
Если селектор элемента начинается с ?, то этот слот является необязательным.
Например, объект транклюзии { slotA: '?myCustomElement' } сопоставляет элементы <my-custom-element> со слотом slotA, к которому можно получить доступ через функцию $transclude или через директиву ngTransclude.
Слоты, которые не помечены как необязательные (?), вызовут ошибку времени компиляции, если в содержимом транклюзии нет соответствующих элементов. Если вы хотите узнать, был ли необязательный слот заполнен содержимым, то вы можете вызвать $transclude.isSlotFilled(slotName) на функции транклюзии, переданной в функцию связывания директивы и инъектируемой в контроллер директивы.
Функции транклюзии
Когда директива запрашивает транклюзию, компилятор извлекает её содержимое и предоставляет функцию транклюзии функции link директивы и controller. Эта функция транклюзии — это специальная функция связывания, которая вернёт скомпилированное содержимое, связанное с новой областью видимости транклюзии.
ngTransclude, то вам не нужно беспокоиться об этой функции, так как ngTransclude сделает это за вас. Если вы хотите вручную управлять вставкой и удалением содержимого транклюзии в своей директиве, то вы должны использовать эту функцию транклюзии. Когда вы вызываете функцию транклюзии, она возвращает объект jqLite/JQuery, содержащий скомпилированный DOM, который связан с правильной областью видимости транклюзии.
Когда вы вызываете функцию транклюзии, вы можете передать функцию привязки к клону. Эта функция принимает два параметра, function(clone, scope) { ... }, где clone — свежий скомпилированный дубликат вашего содержимого транклюзии, а scope — новая созданная область видимости транклюзии, к которой будет привязано дублирование.
cloneFn (функцию привязки к клону), когда вы вызываете функцию транклюзии, так как тогда вы получаете свежий дубликат исходного DOM, а также имеете доступ к новой области видимости транклюзии. Обычная практика — прикреплять содержимое транклюзии (clone) к DOM внутри функции привязки к клону:
var transcludedContent, transclusionScope;
$transclude(function(clone, scope) {
element.append(clone);
transcludedContent = clone;
transclusionScope = scope;
});
Позже, если вы хотите удалить содержимое транклюзии из своего DOM, вы также должны уничтожить связанную область видимости транклюзии:
transcludedContent.remove(); transclusionScope.$destroy();
element.remove() для удаления), то вы также несёте ответственность за вызов $destroy для области видимости транклюзии. Встроенные директивы манипулирования DOM, такие как ngIf, ngSwitch и ngRepeat, автоматически уничтожают свои клоны транклюзии по мере необходимости, поэтому вам не нужно беспокоиться об этом, если вы просто используете ngTransclude для вставки транклюзии в свою директиву.
Области видимости транклюзии
При вызове функции транклюзии возвращается фрагмент DOM, предварительно привязанный к области видимости транклюзии. Эта область видимости является специальной, так как она является дочерней по отношению к области видимости директивы (и поэтому уничтожается при уничтожении области видимости директивы), но она наследует свойства области видимости, из которой была взята.
Например, рассмотрим директиву, использующую транклюзию и изолированную область видимости. Иерархия DOM может выглядеть следующим образом:
<div ng-app>
<div isolate>
<div transclusion>
</div>
</div>
</div>
Иерархия областей видимости $parent будет выглядеть следующим образом:
- $rootScope
- isolate
- transclusion
но области видимости будут наследоваться прототипически от разных областей видимости к их $parent.
- $rootScope - transclusion - isolate
Атрибуты
Объект Атрибутов — передается в качестве параметра в функциях link() или compile(). Он имеет различные применения.
-
Доступ к нормализованным именам атрибутов: Такие директивы, как 'ngBind', могут быть выражены многими способами: 'ng:bind',
data-ng-bindили 'x-ng-bind'. Объект атрибутов позволяет получать нормализованный доступ к атрибутам. -
Взаимодействие между директивами: Все директивы делят один экземпляр объекта атрибутов, что позволяет директивам использовать объект атрибутов для взаимодействия между директивами.
-
Поддержка интерполяции: Атрибуты интерполяции присваиваются объекту атрибутов, что позволяет другим директивам считывать интерполированное значение.
-
Наблюдение за изменениями интерполированных атрибутов: Используйте
$observeдля наблюдения за изменениями значений атрибутов, содержащих интерполяцию (например,src="{{bar}}"). Это не только очень эффективно, но и единственный способ легко получить фактическое значение, потому что во время фазы связывания интерполяция ещё не была оценена, и поэтому значение в настоящее время установлено вundefined.
function linkingFn(scope, elm, attrs, ctrl) {
// get the attribute value
console.log(attrs.ngModel);
// change the attribute
attrs.$set('ngModel', 'new value');
// observe changes to interpolated attribute
attrs.$observe('ngModel', function(value) {
console.log('ngModel has changed value to ' + value);
});
}
module.directive. Приведённый ниже пример иллюстрирует работу $compile. Известные проблемы
Двойная компиляция
Двойная компиляция происходит, когда уже скомпилированная часть DOM компилируется снова. Это нежелательный эффект и может привести к неправильному поведению директив, проблемам производительности и утечкам памяти. Обратитесь к руководству по компилятору раздел о двойной компиляции для подробного объяснения и способов её предотвращения.
Проблемы с replace: true
replace: true устарело и не рекомендуется к использованию, в основном из-за проблем, перечисленных здесь. Оно полностью удалено в новом Angular. Значения атрибутов не объединяются
Когда директива replace сталкивается с одинаковым атрибутом в исходном и замещающем узле, она просто дублирует атрибут и объединяет значения пробелом или символом ; в случае атрибута style.
Original Node: <span class="original" style="color: red;"></span> Replace Template: <span class="replaced" style="background: blue;"></span> Result: <span class="original replaced" style="color: red; background: blue;"></span>
Это означает, что атрибуты, содержащие выражения AngularJS, не будут правильно объединены, например, ngShow или ngClass вызовут ошибку $parse:
Original Node: <span ng-class="{'something': something}" ng-show="!condition"></span>
Replace Template: <span ng-class="{'else': else}" ng-show="otherCondition"></span>
Result: <span ng-class="{'something': something} {'else': else}" ng-show="!condition otherCondition"></span>
См. вопрос #5695.
Директивы не дублируются перед компиляцией
Когда исходный узел и шаблон замещения объявляют одни и те же директивы, они будут скомпилированы дважды, потому что компилятор не дублирует их. Во многих случаях это незаметно, но, например, ngModel прикрепит $formatters и $parsers дважды.
См. вопрос #2573.
transclude: элемент в корне шаблон замещения может иметь непредвиденные последствия
Когда шаблон замещения содержит директиву в корневом узле, использующей transclude: element, например, ngIf или ngRepeat, структура DOM или наследование области видимости могут быть некорректными. См. следующие вопросы:
Использование
$compile(element, transclude, maxPriority);
Аргументы
| Параметр | Тип | Подробности |
|---|---|---|
| element | stringDOMElement | Элемент или строка HTML для компиляции в функцию шаблона. |
| transclude | function(angular.Scope, cloneAttachFn=) | функция, доступная для директив — УСТАРЕЛО. Примечание: Передача функции transclude в функцию $compile устарела, так как она, например, не будет использовать правильную внешнюю область видимости. Пожалуйста, передайте функцию transclude в качестве parentBoundTranscludeFn функции link вместо этого. |
| maxPriority | number | применить только директивы с приоритетом ниже заданного (только влияет на корневые элементы, а не на их дочерние элементы) |
Возвращаемое значение
function(scope, cloneAttachFn=, options=) |
функция link, которая используется для привязки шаблона (элемента/дерева DOM) к области видимости. Где:
Вызов функции link возвращает элемент шаблона. Это либо исходный переданный элемент, либо клон элемента, если задан После привязки представление не обновляется до вызова $digest, который обычно выполняется AngularJS автоматически. Если вам нужен доступ к привязанному представлению, есть два способа сделать это:
Для получения информации о работе компилятора, см. раздел «Компилятор AngularJS HTML» в Руководстве разработчика. |
© 2010–2018 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.7.8/docs/api/ng/service/$compile