Angular JS: Какая потребность в функции ссылок директив, если у нас уже есть контроллер с областью?

Мне нужно выполнить некоторые операции с областью действия и шаблоном. Кажется, что я могу сделать это либо в функции link, либо в функции controller (так как у обоих есть доступ к области).

Когда это происходит, когда мне нужно использовать функцию link, а не контроллер?

angular.module('myApp').directive('abc', function($timeout) {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: true,
        link: function(scope, elem, attr) { /* link function */ },
        controller: function($scope, $element) { /* controller function */ }
    };
}

Кроме того, я понимаю, что link - это мир не angular. Поэтому я могу использовать $watch, $digest и $apply.

Каково значение функции link, когда у нас уже был контроллер?

Ответ 1

После моей начальной борьбы с функциями link и controller и чтения о них много, я думаю, теперь у меня есть ответ.

Сначала позволяет понимать,

Как директивы angular работают в двух словах:

  • Начнем с шаблона (в виде строки или загруженного в строку)

    var templateString = '<div my-directive>{{5 + 10}}</div>';

  • Теперь этот templateString завернут как элемент angular

    var el = angular.element(templateString);

  • С el теперь мы скомпилируем его с помощью $compile, чтобы вернуть функцию link.

    var l = $compile(el)

    Вот что происходит,

    • $compile просматривает весь шаблон и собирает все директивы, которые он распознает.
    • Все обнаруженные директивы скомпилированы рекурсивно, и их функции link собраны.
    • Затем все функции link завертываются в новую функцию link и возвращаются как l.
  • Наконец, мы предоставляем функцию scope этой функции l (link), которая дополнительно выполняет связанные функции привязки с этим scope и их соответствующими элементами.

    l(scope)

  • Это добавляет template в качестве нового node к DOM и вызывает controller, который добавляет свои часы в область , которая совместно используется с шаблоном в DOM.

enter image description here

Сравнение компилирования vs link vs контроллера:

  • Каждая директива скомпилирована только один раз, а функция ссылка сохраняется для повторного использования. Поэтому, если в директиве compile должно выполняться что-то, применимое ко всем экземплярам директивы.

  • Теперь после компиляции мы имеем функцию link, которая выполняется при прикреплении шаблона к DOM. Поэтому мы выполняем все, что характерно для каждого экземпляра директивы. Например: прикрепление событий, , изменение шаблона на основе области и т.д.

  • Наконец, контроллер должен быть доступен как живым, так и реактивным, в то время как директива работает на DOM (после присоединения). Поэтому:

    (1) После настройки представления [ V] (т.е. шаблона) со ссылкой. $scope является нашей [ M], а $controller является нашей [ C] в M V C

    (2) Воспользуйтесь привязкой 2-way с $scope, настроив часы.

    (3) $scope ожидается, что часы будут добавлены в контроллер, так как это то, что наблюдает за шаблоном во время выполнения.

    (4) Наконец, controller также используется для связи между связанными директивами. (Пример myTabs в https://docs.angularjs.org/guide/directive)

    (5) Это правда, что мы могли бы сделать все это в функции link, а также о разделении проблем.

Поэтому, наконец, мы имеем следующее, которое идеально подходит ко всем частям:

enter image description here

Ответ 2

Для чего нужны контроллеры

Разница между link и controller вступает в игру, когда вы хотите вставлять директивы в DOM и выставлять функции API из родительской директивы в вложенные.

Из docs:

Best Practice: используйте контроллер, если вы хотите открыть API для других директив. В противном случае используйте ссылку.

Предположим, что у вас есть две директивы my-form и my-text-input, и вы хотите, чтобы директива my-text-input отображалась только внутри my-form и нигде больше.

В этом случае вы укажете при определении директивы my-text-input, что для этого требуется контроллер из элемента parent DOM с помощью аргумента require, вот так: require: '^myForm'. Теперь контроллер из родительского элемента будет injected в функцию link в качестве четвертого аргумента, следуя за $scope, element, attributes. Вы можете вызывать функции на этом контроллере и взаимодействовать с родительской директивой.

Кроме того, если такой контроллер не найден, ошибка будет повышена.

Зачем использовать ссылку вообще

Нет реальной необходимости использовать функцию link, если она определяет controller, поскольку $scope доступен на controller. Кроме того, определяя как link, так и controller, нужно быть осторожным относительно порядка вызова двух (controller выполняется раньше).

Однако, в соответствии с методом Angular, большинство манипуляций с DOM и двухсторонняя привязка с использованием $watchers обычно выполняются в функции link, тогда как API для детей и $scope выполняется в controller. Это не сложное и быстрое правило, но при этом код будет более модульным и поможет в разделении проблем (контроллер будет поддерживать состояние directive, а функция link будет поддерживать внешние привязки DOM +).

Ответ 3

Функция/t controller представляет собой абстракцию модели-представления-контроллера (MVC). Хотя о MVC нет ничего нового, он по-прежнему является самым значительным преимуществом angular: разделить проблемы на более мелкие части. И что это, не более того, поэтому, если вам нужно реагировать на Model изменения, исходящие от View, controller является правильным человеком для выполнения этой работы.

История о функции link различна, она исходит с другой точки зрения, а затем с MVC. И действительно важно, как только мы хотим пересечь границы controller/model/view (шаблон).

Давайте начнем с параметров, которые передаются в функцию link:

function link(scope, element, attrs) {
  • область - объект области Angular. Элемент
  • - это элемент, обернутый jqLite, который соответствует этой директиве.
  • attrs - это объект с нормализованными именами атрибутов и их соответствующими значениями.

Чтобы помещать link в контекст, следует упомянуть, что все директивы проходят эти шаги процесса инициализации: Compile, Link. Извлечение из книги Брэда Грина и Шьяма Сешадри Angular JS:

Скомпилировать фазу (сестра ссылки, давайте укажем здесь, чтобы получить четкое изображение):

В этой фазе Angular проходит DOM, чтобы идентифицировать все зарегистрированные  директивы в шаблоне. Для каждой директивы она преобразует  DOM на основе правил директив (шаблон, замена, переключение и  и так далее) и вызывает функцию компиляции, если она существует. Результатом является  скомпилированная функция шаблона,

Фаза связи:

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

Хороший пример использования link можно найти здесь: Создание пользовательских директив. См. Пример: Создание директивы, которая манипулирует DOM, которая вставляет "дату-время" на страницу, обновляемую каждую секунду.

Просто очень короткий фрагмент из этого богатого источника выше, показывая реальные манипуляции с DOM. Функция $hookout подключена к функции $timeout, а также очищается в вызове деструктора, чтобы избежать утечек памяти.

.directive('myCurrentTime', function($timeout, dateFilter) {

 function link(scope, element, attrs) {

 ...

 // the not MVC job must be done
 function updateTime() {
   element.text(dateFilter(new Date(), format)); // here we are manipulating the DOM
 }

 function scheduleUpdate() {
   // save the timeoutId for canceling
   timeoutId = $timeout(function() {
     updateTime(); // update DOM
     scheduleUpdate(); // schedule the next update
   }, 1000);
 }

 element.on('$destroy', function() {
   $timeout.cancel(timeoutId);
 });

 ...

Ответ 4

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