Spec-Zone.ru › Angular.js 1.5

Улучшить эту документацию Просмотреть исходный код $compile

  1. $compileProvider
  2. сервис в модуле 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) { ... }
});

Методы жизненного цикла

Контроллеры директивы могут предоставлять следующие методы, вызываемые Angular в определённые моменты жизненного цикла директивы:

  • $onInit() - Вызывается для каждого контроллера после того, как все контроллеры на элементе были созданы и их привязки были инициализированы (и до функций пред- и пост-связывания для директив на этом элементе). Это хорошее место для размещения кода инициализации для вашего контроллера.
  • $onChanges(changesObj) - Вызывается при обновлении односторонних (<) или интерполяционных (@) привязок. changesObj — это хеш, ключи которого — имена изменённых связанных свойств, а значения — объекты вида { currentValue, previousValue, isFirstChange() }. Используйте этот метод для запуска обновлений внутри компонента, например, для клонирования связанного значения, чтобы предотвратить случайное изменение внешнего значения.
  • $doCheck() - Вызывается на каждой итерации цикла переваривания. Предоставляет возможность обнаруживать и обрабатывать изменения. Любые действия, которые вы хотите выполнить в ответ на обнаруженные изменения, должны быть вызваны из этого метода; реализация этого не влияет на время вызова $onChanges. Например, этот метод может быть полезен, если вы хотите выполнить проверку глубокого равенства или проверку объекта Date, изменения которого не будут обнаружены детектором изменений Angular и, следовательно, не будут вызывать $onChanges. Этот метод вызывается без аргументов; если вы обнаруживаете изменения, необходимо сохранить предыдущее(ые) значение(я) для сравнения с текущими значениями.
  • $onDestroy() - Вызывается для контроллера, когда содержащий его scope уничтожается. Используйте этот метод для освобождения внешних ресурсов, watch и обработчиков событий. Обратите внимание, что методы $onDestroy() компонентов вызываются в том же порядке, что и события $scope.$broadcast, сверху вниз. Это означает, что метод $onDestroy() родительского компонента будет вызван до метода $onDestroy() дочерних компонентов.
  • $postLink() - Вызывается после того, как элемент этого контроллера и его дочерние элементы были связаны. Подобно функции post-link, этот метод можно использовать для настройки обработчиков событий DOM и выполнения прямой манипуляции с DOM. Обратите внимание, что дочерние элементы, содержащие templateUrl директивы, не будут скомпилированы и связаны, поскольку они ожидают загрузки своего шаблона асинхронно, и их компиляция и связывание приостановлены до тех пор, пока это не произойдёт.

Сравнение с методами жизненного цикла Angular 2

Angular 2 также использует методы жизненного цикла для своих компонентов. Хотя методы жизненного цикла Angular 1 похожи, есть некоторые различия, о которых следует знать, особенно при переносе кода из Angular 1 в Angular 2:

  • Методы жизненного цикла Angular 1 имеют префикс $, например $onInit. Методы жизненного цикла Angular 2 имеют префикс ng, например ngOnInit.
  • Методы жизненного цикла Angular 1 можно определить в прототипе контроллера или добавить в контроллер внутри его конструктора. В Angular 2 вы можете определять методы только в прототипе класса Component.
  • Из-за различий в обнаружении изменений, вы можете получить значительно больше вызовов $doCheck в Angular 1, чем ngDoCheck в Angular 2
  • Изменения модели внутри $doCheck вызовут новые циклы переваривания, что приведёт к распространению изменений по всему приложению. Angular 2 не позволяет методу 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.

Объект хеш 'isolate' 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 и наоборот. Необязательные атрибуты должны быть помечены вопросительным знаком: =? или =?attr. Если выражение привязки не является присваиваемым, или если атрибут не является необязательным и не существует, при обнаружении изменений локального значения будет выброшено исключение ($compile:nonassign), так как будет невозможно синхронизировать их обратно в родительский контекст. По умолчанию используется метод $watch для отслеживания изменений, а проверка на равенство основана на идентичности объекта. Однако, если в качестве выражения привязки передаётся литерал объекта или литерал массива, проверка на равенство выполняется по значению (используя функцию angular.equals). Также можно отслеживать вычисленное значение поверхностно с помощью $watchCollection: используйте =* или =*attr (=*? или =*?attr если атрибут является необязательным).

  • < или <attr — устанавливает одностороннюю привязку между свойством локального контекста и выражением, переданным через атрибут attr. Выражение оценивается в контексте родительского контекста. Если имя attr не указано, то имя атрибута предполагается таким же, как и локальное имя. Также вы можете сделать привязку необязательной, добавив ?: <? или <?attr.

    Например, при <my-component my-attr="parentModel"> и определении директивы scope: { localModel:'<myAttr' }, свойство изолированного контекста localModel будет отражать значение parentModel в родительском контексте. Любые изменения в parentModel будут отражаться в localModel, но изменения в localModel не будут отражаться в parentModel. Однако есть два нюанса:

    1. односторонняя привязка не копирует значение из родителя в изолированный контекст, она просто устанавливает то же самое значение. Это означает, что если ваше связанное значение — объект, изменения его свойств в изолированном контексте будут отражаться в родительском контексте (поскольку оба ссылаются на один и тот же объект).
    2. односторонняя привязка отслеживает изменения идентичности родительского значения. Это означает, что $watch для родительского значения срабатывает только в том случае, если ссылка на значение изменилась. В большинстве случаев это не должно вызывать беспокойства, но может быть важно знать, если вы связываете односторонне объект, а затем заменяете этот объект в изолированном контексте. Если теперь вы измените свойство объекта в родительском контексте, изменение не будет распространено в изолированный контекст, потому что идентичность объекта в родительском контексте не изменилась. Вместо этого вы должны присвоить новый объект.

    Односторонняя привязка полезна, если вы не планируете распространять изменения обратных привязок изолированного контекста обратно в родительский. Однако это не делает это совершенно невозможным.

  • & или &attr — предоставляет способ выполнения выражения в контексте родительского контекста. Если имя attr не указано, то имя атрибута предполагается таким же, как и локальное имя. Учитывая <my-component my-attr="count = count + value"> и определение изолированного контекста scope: { localFn:'&myAttr' }, свойство изолированного контекста localFn будет указывать на функцию-обёртку для выражения count = count + value. Зачастую нужно передавать данные из изолированного контекста через выражение в родительский контекст. Это можно сделать, передав карту имён локальных переменных и их значений в функцию-обёртку fn. Например, если выражение increment(amount), то мы можем указать значение amount, вызвав localFn как localFn({amount: 22}).

В целом, можно применять несколько директив к одному элементу, но могут быть ограничения в зависимости от типа контекста, необходимого для директив. Следующие пункты помогут объяснить эти ограничения. Для простоты рассматриваются только две директивы, но это также применимо для нескольких директив:

  • без контекста + без контекста => Две директивы, которым не нужен собственный контекст, будут использовать контекст своего родителя
  • дочерний контекст + без контекста => Обе директивы будут использовать один единственный дочерний контекст
  • дочерний контекст + дочерний контекст => Обе директивы будут использовать один единственный дочерний контекст
  • изолированный контекст + без контекста => Директива с изолированным контекстом будет использовать свой собственный созданный изолированный контекст. Другая директива будет использовать контекст своего родителя
  • изолированный контекст + дочерний контекст => Не сработает! Только один контекст может быть связан с одним элементом. Поэтому эти директивы не могут быть применены к одному и тому же элементу.
  • изолированный контекст + изолированный контекст => Не сработает! Только один контекст может быть связан с одним элементом. Поэтому эти директивы не могут быть применены к одному и тому же элементу.

bindToController

Это свойство используется для привязки свойств контекста непосредственно к контроллеру. Оно может быть либо true, либо объектом с таким же форматом, как и свойство scope.

Когда для директивы используется изолированный контекст (см. выше), bindToController: true позволит компоненту привязать свои свойства к контроллеру, а не к контексту.

После создания контроллера начальные значения привязок изолированного контекста будут привязаны к свойствам контроллера. Вы можете получить доступ к этим привязки после их инициализации, предоставив метод контроллера с именем $onInit, который вызывается после того, как все контроллеры на элементе будут созданы и их привязки будут инициализированы.

Предупреждение о устаревании: хотя привязки для контроллеров без ES6 сейчас связываются с this до вызова конструктора контроллера, это использование теперь устарело. Пожалуйста, поместите код инициализации, который зависит от привязок, в метод $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 может быть строкой, массивом или объектом:

  • строка, содержащая имя директивы для передачи функции привязки
  • массив, содержащий имена директив для передачи функции привязки. Аргумент, передаваемый функции привязки, будет массивом контроллеров в том же порядке, что и имена в свойстве require
  • объект, значения свойств которого — имена директив для передачи функции привязки. Аргумент, передаваемый функции привязки, также будет объектом с соответствующими ключами, значения которых будут содержать соответствующие контроллеры.

Если свойство 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 истинно — УСТАРЕЛО).
  • Оборачивать содержимое элемента директивы (если transclude истинно).

Значение может быть:

  • Строкой. Например, <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 ([УСТАРЕЛО!], будет удалено в следующей основной версии — т.е. v2.0)

указать, что должен заменить шаблон. По умолчанию false.

  • true - шаблон заменит элемент директивы.
  • false - шаблон заменит содержимое элемента директивы.

Процесс замены мигрирует все атрибуты/классы со старого элемента на новый. См. Руководство по директивам для примера.

Есть очень мало сценариев, где требуется замена элемента для работы приложения, основным из которых являются повторно используемые пользовательские компоненты, используемые в контексте SVG (потому что SVG не работает с пользовательскими элементами в дереве DOM).

transclude

Извлечь содержимое элемента, где появляется директива, и сделать его доступным для директивы. Содержимое компилируется и предоставляется директиве как функция трансклюзии. См. раздел Трансклюзия ниже.

compile

function compile(tElement, tAttrs, transclude) { ... }

Функция compile обрабатывает преобразование шаблона DOM. Поскольку большинство директив не выполняют преобразование шаблона, она используется нечасто. Функция compile принимает следующие аргументы:

  • tElement - элемент шаблона - Элемент, где объявлена директива. Можно безопасно выполнять преобразование шаблона только на элементе и его дочерних элементах.

  • tAttrs - атрибуты шаблона - Нормализованный список атрибутов, объявленных на этом элементе, общий для всех функций компиляции директив.

  • transclude - [УСТАРЕЛО!] Функция связывания трансклюзии: function(scope, cloneLinkingFn)

Примечание: Экземпляр шаблона и экземпляр связи могут быть разными объектами, если шаблон был скопирован. По этой причине небезопасно выполнять что-либо, кроме преобразований DOM, которые применяются ко всем клонированным узлам DOM внутри функции compile. В частности, регистрация обработчиков событий DOM должна выполняться в функции link, а не в функции compile.
Примечание: Функция compile не может обрабатывать директивы, которые рекурсивно используют себя в своих собственных шаблонах или функциях compile. Компиляция таких директив приводит к бесконечному циклу и ошибкам переполнения стека. Этого можно избежать, вручную используя $compile в функции postLink, чтобы императивно скомпилировать шаблон директивы вместо того, чтобы полагаться на автоматическую компиляцию шаблона через объявление template или templateUrl или ручную компиляцию внутри функции compile.
Примечание: Функция transclude , которая передаётся в функцию compile, устарела, поскольку, например, не знает о правильной внешней области видимости. Используйте вместо неё функцию трансклюзии, которая передаётся в функцию link.

Функция compile может иметь возвращаемое значение, которое может быть функцией или объектом.

  • возвращение функции (post-link) — эквивалентно регистрации функции связывания через свойство link объекта конфигурации, когда функция compile пуста.

  • возвращение объекта с зарегистрированными функциями через свойства pre и post — позволяет управлять тем, когда функция связывания должна вызываться во время фазы связывания. См. информацию о функциях предварительной и последующей связи ниже.

link

Это свойство используется только если свойство compile не определено.

function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }

Функция link отвечает за регистрацию обработчиков событий 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-элементов заключается в том, что транклюдированное содержимое имеет доступ к свойствам области видимости, из которой оно было взято, даже если у директивы изолированная область видимости. См. Руководство по директивам.

Это позволяет виджету иметь личное состояние для своего шаблона, в то время как транклюдированное содержимое имеет доступ к своей исходной области видимости.

Примечание: При тестировании директивы транклюзии элемента вам не следует размещать директиву в корне фрагмента 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();
Рекомендация: Если вы планируете добавлять и удалять транклюдированное содержимое вручную в своей директиве (вызвав функцию транклюзии для получения DOM и вызвав 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 компилируется повторно. Это нежелательный эффект и может привести к неправильной работе директив, проблемам с производительностью и утечкам памяти. Обратитесь к руководству по компилятору, к разделу о двойной компиляции для получения подробного объяснения и способов её предотвращения.

Использование

$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) к контексту. Где:

  • scope - Контекст Scope, к которому нужно привязаться.
  • cloneAttachFn - Если cloneAttachFn предоставлено, то функция link клонирует template и вызовет функцию cloneAttachFn, позволяя вызывающей стороне прикрепить клонированные элементы к документу DOM в нужном месте. Функция cloneAttachFn вызывается как:
    cloneAttachFn(clonedElement, scope) где:

    • clonedElement - Клон исходного element, переданного в компилятор.
    • scope - Текущий контекст, с которым работает функция связывания.
  • options - Необязательный объект-хеш с параметрами связывания. Если options предоставлено, то можно использовать следующие ключи для управления поведением связывания:

    • parentBoundTranscludeFn - Функция transclude, доступная для директивы; если она задана, она будет передана в функции link директивы, найденные в element во время компиляции.
    • transcludeControllers - Объект-хеш с ключами, которые сопоставляют имена контроллеров с хешем, содержащим ключ instance, который сопоставляется с экземпляром контроллера; если он задан, он сделает контроллеры доступными для директивы в compileNode:
      {
        parent: {
          instance: parentControllerInstance
        }
      }
      
    • futureParentElement - Определяет родителя, к которому cloneAttachFn добавит клонированные элементы; необходимо только для transclude, которые могут содержать не HTML-элементы (например, SVG-элементы). Смотрите также свойство directive.controller.

Вызов функции link возвращает элемент шаблона. Это либо исходный переданный элемент, либо клон элемента, если cloneAttachFn предоставлен.

После связывания вид не обновляется до вызова $digest, который обычно выполняется автоматически Angular.

Если вам нужен доступ к привязанному виду, есть два способа:

  • Если вы не просите функцию link клонировать шаблон, создайте DOM-элементы до отправки их в компилятор и сохраните эту ссылку.

    var element = $compile('<p>{{total}}</p>')(scope);
    
  • Если же вам нужен клон элемента, ссылка на вид из исходного примера не будет указывать на клон, а на исходный шаблон, который был клонирован. В этом случае вы можете получить доступ к клону через cloneAttachFn:

    var templateElement = angular.element('<p>{{total}}</p>'),
        scope = ....;
    
    var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
      //attach the clone to DOM document at the right place
    });
    
    //now we have reference to the cloned DOM via `clonedElement`
    

Для получения информации о работе компилятора, см. раздел «Компилятор Angular HTML» в руководстве разработчика.

© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.5.11/docs/api/ng/service/$compile

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API