Связь с компилятором и контроллером

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

В документах они объясняют, что:

  • Функция компиляции и связывания используется в разных фазах angular цикл
  • контроллеры разделяются между директивами

Однако для меня неясно, какой код должен идти туда.

Например: могу ли я создавать функции в компиляции и привязывать их к области действия в ссылке или только прикреплять функции к области в контроллере?

Как контроллеры распределяются между директивами, если каждая директива может иметь свой собственный контроллер? Являются ли контроллеры действительно разделяемыми или это просто свойства области?

Ответ 1

Скомпилировать:

Это фаза, где Angular фактически компилирует вашу директиву. Эта функция компиляции вызывается только один раз для каждой ссылки на данную директиву. Например, предположим, что вы используете директиву ng-repeat. ng-repeat придется искать элемент, к которому он присоединен, извлечь фрагмент html, к которому он присоединен, и создать функцию шаблона.

Если вы использовали HandleBars, шаблоны underscore или их эквивалент, то, как и компиляция их шаблонов для извлечения функции шаблона. К этой функции шаблона вы передаете данные, а возвращаемое значение этой функции - html с данными в правильных местах.

Фаза компиляции - это шаг в Angular, который возвращает функцию шаблона. Эта функция шаблона в Angular называется функцией связывания.

Фаза связывания:

Эта фаза связывания - это привязка данных ($ scope) к функции связывания, и она должна вернуть вам связанный html. Так как директива также указывает, куда идет этот html или что он меняет, это уже хорошо. Это функция, в которой вы хотите внести изменения в связанный html, т.е. Html, который уже имеет прикрепленные к нему данные. В Angular, если вы пишете код в функции связывания, его обычно выполняет функция пост-ссылки (по умолчанию). Это своего рода обратный вызов, который вызывается после того, как функция связывания связала данные с шаблоном.

Контроллер:

Контроллер - это место, где вы вводите определенную логику определенной директивы. Эта логика также может войти в функцию связывания, но тогда вам придется поместить эту логику в область действия, чтобы сделать ее "доступной". Проблема в том, что тогда вы будете развращать область с вашими директивами, что на самом деле не является чем-то, что ожидается. Итак, какова альтернатива, если две Директивы хотят поговорить друг с другом/сотрудничать друг с другом? Конечно, вы можете поместить всю эту логику в сервис, а затем заставить обе эти директивы зависеть от этой службы, но это просто приводит к еще одной зависимости. Альтернативой является предоставление контроллера для этой области (обычно изолировать область?), А затем этот контроллер вводится в другую директиву, когда эта директива "требует" другой. См. Вкладки и панели на первой странице angularjs.org для примера.

Ответ 2

Я хотел добавить и то, что говорит команда O'Reily AngularJS от команды Google:

Контроллер. Создайте контроллер, который публикует API для связи по всем директивам. Хорошим примером является Директива по установлению связи.

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

Компиляция. Программно модифицируйте шаблон DOM для функций в копиях директивы, как при использовании в ng-repeat. Функция компиляции также может возвращать функции ссылок для изменения результирующих экземпляров элемента.

Ответ 3

A directive позволяет расширять словарь HTML декларативным способом для создания веб-компонентов. Атрибут ng-app является директивой, поэтому ng-controller и все ng- prefixed attributes. Директивы могут быть attributes, tags или даже class names, comments.

Как рождаются директивы (compilation и instantiation)

Скомпилировать: Хорошо использовать функцию compile как для manipulate DOM перед ее визуализацией, так и вернуть функцию link (которая будет обрабатывать ссылку для нас). Это также место для размещения любых методов, которые необходимо обменивать со всеми instances этой директивой.

ссылка: Хорошо использовать функцию link для регистрации всех слушателей на определенном элементе DOM (который клонируется из шаблона) и настроить наши привязки к странице.

Если установлено в функции compile(), они были бы установлены только один раз (что часто бывает так, как вы хотите). Если они установлены в функции link(), они будут устанавливаться каждый раз, когда элемент HTML привязан к данным в объекте .

<div ng-repeat="i in [0,1,2]">
    <simple>
        <div>Inner content</div>
    </simple>
</div>

app.directive("simple", function(){
   return {
     restrict: "EA",
     transclude:true,
     template:"<div>{{label}}<div ng-transclude></div></div>",        
     compile: function(element, attributes){  
     return {
             pre: function(scope, element, attributes, controller, transcludeFn){

             },
             post: function(scope, element, attributes, controller, transcludeFn){

             }
         }
     },
     controller: function($scope){

     }
   };
});
Функция

compile возвращает функцию ссылки pre и post. В функции предварительной ссылки у нас есть шаблон экземпляра, а также область действия из controller, но тем не менее шаблон не связан с областью действия и до сих пор не имеет транксированного содержимого.

post Функция ссылки - это когда post link является последней выполняемой функцией. Теперь transclusion завершен, the template is linked to a scope и view will update with data bound values after the next digest cycle. Опция link - это просто ярлык для настройки функции post-link.

:. Контроллер директивы может быть передан на другую фазу связывания/компиляции. Он может быть введен в другие руководства как средство для использования в межстраничной коммуникации.

Необходимо указать имя требуемой директивы - оно должно быть привязано к одному элементу или его родительскому элементу. Имя может иметь префикс:

? – Will not raise any error if a mentioned directive does not exist.
^ – Will look for the directive on parent elements, if not available on the same element.

Используйте квадратную скобку [‘directive1′, ‘directive2′, ‘directive3′], чтобы потребовать несколько контроллеров директив.

var app = angular.module('app', []);

app.controller('MainCtrl', function($scope, $element) {
});

app.directive('parentDirective', function() {
  return {
    restrict: 'E',
    template: '<child-directive></child-directive>',
    controller: function($scope, $element){
      this.variable = "Hi Vinothbabu"
    }
  }
});

app.directive('childDirective', function() {
  return {
    restrict:  'E',
    template: '<h1>I am child</h1>',
    replace: true,
    require: '^parentDirective',
    link: function($scope, $element, attr, parentDirectCtrl){
      //you now have access to parentDirectCtrl.variable
    }
  }
});

Ответ 4

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

controller: function($scope, $exceptionHandler, $attr, $element, $parse, $myOtherService, someCrazyDependency) {...

против.

link: function(scope, element, attrs) {... //no services allowed

Ответ 5

это хороший образец для понимания фаз директивы http://codepen.io/anon/pen/oXMdBQ?editors=101

var app = angular.module('myapp', [])

app.directive('slngStylePrelink', function() {
    return {
        scope: {
            drctvName: '@'
        },
        controller: function($scope) {
            console.log('controller for ', $scope.drctvName);
        },
        compile: function(element, attr) {
            console.log("compile for ", attr.name)
            return {
                post: function($scope, element, attr) {
                    console.log('post link for ', attr.name)
                },
                pre: function($scope, element, attr) {
                    $scope.element = element;
                    console.log('pre link for ', attr.name)
                        // from angular.js 1.4.1
                    function ngStyleWatchAction(newStyles, oldStyles) {
                        if (oldStyles && (newStyles !== oldStyles)) {
                            forEach(oldStyles, function(val, style) {
                                element.css(style, '');
                            });
                        }
                        if (newStyles) element.css(newStyles);
                    }

                    $scope.$watch(attr.slngStylePrelink, ngStyleWatchAction, true);

                    // Run immediately, because the watcher first run is async
                    ngStyleWatchAction($scope.$eval(attr.slngStylePrelink));
                }
            };
        }
    };
});

HTML

<body ng-app="myapp">
    <div slng-style-prelink="{height:'500px'}" drctv-name='parent' style="border:1px solid" name="parent">
        <div slng-style-prelink="{height:'50%'}" drctv-name='child' style="border:1px solid red" name='child'>
        </div>
    </div>
</body>

Ответ 6

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