Контроллеры директив в AngularJS

Немного о контроллерах директив. Зачем они нужны и чем отличаются от функции link.Контроллер директивы vs контроллер видаОбъявление контроллера в директиве: app.controller ('myCtrl', function ($scope, $element, $attrs) { this.name = 'myCtrl' )

app.directive ('myDirective', function () { return { controller: 'myCtrl', link: function (scope, element, attrs, ctrl) { console.log (ctrl.name) //'myCtrl' } } }); Вопрос на засыпку. Чем отличается контроллер директивы, от контроллера вида, который мы указываем через ng-controller (или другим способом)?

Да ничем. Это одно и то же. Если мы используем его в директиве, то в параметры $scope, $element, $attrs приходит область видимости и элемент директивы, если в шаблоне — приходит область видимости и параметры элемента, на котором висит ng-controller.

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

Контроллер директивы vs link Разбираемся дальше. В объекте определения директивы есть хорошо известная функция link, которая, на первый взгляд, ничем не отличается от контроллера. Но отличия все же есть.Во-первых, она вызывается позже контроллера. Последовательность вызовов такая: controller, preLink, postLink (postLink это и есть link. Подробнее в документации). Контроллер срабатывает даже раньше чем инициализируются директивы вложенных элементов. Поэтому в $scope, например, можно записать настройки для дочерних директив.

Во-вторых, в link передается ссылка на контроллер.

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

Пример использования сторонних контроллеров в директиве, чтобы не отрываться от кода:

app.directive ('parent', function () { return { controller: 'parentCtrl', link: function (scope, element, attrs, ctrl) { console.log (ctrl); //parentCtrl. Здесь будет собственный контроллер директивы } } });

app.directive ('children', function () { return { require: '^parent', controller: 'childrenCtrl', link: function (scope, element, attrs, ctrl) { console.log (ctrl); //parentCtrl. А сюда уже попадет только контроллер родительской директивы, объявленой в require. //Помните об этом каждый раз, когда выносите код директивы в контроллер. //Вполне возможно, что потом захотите использовать в директиве методы чужого контроллера, //который затрет ссылку на ваш контроллер. } } })

app.directive ('baby', function () { return { restrict: 'E', require: ['^parent', '^children'], link: function (scope, element, attrs, ctrls) { console.log (ctrls); //[parentCtrl, childrenCtrl]. Тем не менее контроллер из children будет доступен в дочерней директиве } } }) Живой пример в планкереВ controller мы создаем экземпляр контроллера, в require обращаемся к созданным экземплярам, что дает возможность хранить в контроллере общие данные.

Можно выделить два случая использования контроллеров: разделение общих методов между разными директивами, как работает, например, ngModelController в Ангуляре, и использование вложенными директивами данных родительской директивы, как работают табы, карусели и т.п., где есть родитель-контейнер и вложенные элементы. Если в первом случае контроллер работает как набор абстрактных методов, то во втором — может хранить в себе ссылку на список элементов, номер активного элемента, общее количество элементов и другую общую информацию. Конечно, для этой цели допустимо использование $scope, но, очевидно, оно будет не по назначению, т.к. область видимости нужна прежде всего для связывания контроллера с видом, а не для разделения общих данных.

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

© Habrahabr.ru