Ссылка против компиляции против контроллера

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

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

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

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

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

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


person schacki    schedule 28.03.2013    source источник
comment
См. Также разницу stackoverflow.com/questions/12546945/   -  person Mark Rajcok    schedule 28.03.2013
comment
Возможно, более подробный обзор функций директив: Angular директивы - когда использовать компиляцию, контроллер, предварительную ссылку и пост-ссылку.   -  person Izhaki    schedule 07.07.2014
comment
Написал пост со схемой жизненного цикла директивы (этап создания). Может быть, это кому-то поможет: filimanjaro.com/2014/   -  person average Joe    schedule 22.10.2014


Ответы (6)


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

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

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

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

Этап установления связи:

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

Контроллер:

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

person ganaraj    schedule 28.03.2013
comment
Чтобы уточнить: compile компилирует шаблон, который будет использоваться на всей странице. Компоновщик привязан к каждому экземпляру. Верно? Затем контроллер работает между экземплярами. - person Zlatko; 22.01.2014
comment
Итак, контроллеры общаются с другими контроллерами с помощью службы, а директивы взаимодействуют с другими директивами, используя другую директиву, которую требует каждая директива? Похоже, было бы проще просто использовать Сервисы для общих данных, вам по-прежнему требуется зависимость для каждого, но в этом случае у вас нет двух типов директив. Одна используется как мета-директива / служебная штука, а другая - обычная директива ... - person user2483724; 12.03.2014
comment
Исправление вышеупомянутого комментария. Я обнаружил, что это полезно, потому что директива хочет взаимодействовать с другой директивой, чтобы использовать некоторые из ее функций. Затем этот метод позволяет директивам расширять функциональность другой директивы. - person user2483724; 13.03.2014
comment
действительно хороший ответ, было бы очень хорошо с изображением, которое показывает карту разума о том, как все должно работать на angular, иногда это действительно сбивает с толку, так как некоторые люди говорят о сервисах, а затем определяют его как фабрику, я предполагаю, что с самого начала что твой будет бегать по разным заказам ... - person Martea; 27.08.2014
comment
@CMCDragonkai для каждой директивы controller функция выполняется после компиляции, но до pre-link в локальной ветви дерева DOM. Также функции controller и pre-link выполняются с обходом локальной ветки DOM сверху вниз. После этого post-link выполняется снизу вверх. - person Artem Platonov; 30.09.2014
comment
Итак ... поскольку вы можете вставить $ element в контроллер директивы, почему бы просто не всегда использовать контроллер? Каковы фактические преимущества использования функции ссылки? - person RavenHursT; 07.10.2014
comment
Это только беспорядок, если вы этого не понимаете. У него есть причина делать то, что он делает. - person demisx; 24.02.2015
comment
Это правильный технический ответ, однако у меня все еще остаются вопросы о том, когда мне следует использовать функцию ссылки. - person Nicholas Marshall; 12.05.2015
comment
Если ваша директива имеет изолированную область видимости, я не уверен, почему прикрепление к ней чего-либо с помощью функции post-link больше загрязняет, чем выполнение этого в контроллере. - person Casey; 08.09.2015
comment
@demisx, понимая беспорядок, волшебным образом не превращает его в беспорядок. большая часть несвободного кода представляет собой беспорядок, и люди, создавшие его, это понимают. Причина того, как ng 1.x работает именно так, - это накопление гнили, и это одна из причин, по которой команда ng отказывается от него. - person jajdoo; 07.12.2015
comment
Должны ли мы везде использовать controller вместо link? Так что мне не нужно менять код в будущем, если нужно поделиться методом или ввести какую-то логику? Есть ли подводные камни в использовании постоянно controller вместо ссылки? - person JPS; 14.12.2015
comment
Я полагаю, что вся эта сложность была необходима при разработке собственных директив angular, возможно, в модулях сторонних разработчиков, но для разработчиков, использующих библиотеку, это слишком сложно, то же самое с включением. У людей не так много времени, чтобы изучить новую структуру, большинство людей просто попытаются найти причину этих сложных вещей. - person Paolo; 13.08.2017

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

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

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

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

person Nicholas Dynan    schedule 04.06.2014
comment
Вашу ссылку на thinkster.io нельзя смотреть без оплаты. Не моя ссылка, но, возможно, это более подходит: toddmotto.com/directive- to-directive-communication-with-require - person R. van Twisk; 15.01.2017

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

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

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

link: мы будем использовать функцию 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 функция ссылки - это функция, которую нужно выполнить последней. Теперь transclusion завершен, the template is linked to a scope и view will update with data bound values after the next digest cycle. Параметр link - это просто ярлык для настройки функции post-link.

controller: Директива controller может быть передана на этап компоновки / компиляции другой директивы. Его можно вводить в другие директивы как средство для использования в междирективном общении.

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

? – 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
    }
  }
});
person Thalaivar    schedule 29.09.2015
comment
вы упомянули, что показали, как получить parentDirectiveCtrl в дочернем контроллере ... в этом примере у дочернего элемента нет контроллера, а скорее функция ссылки ... Я не застрял в этой проблеме в настоящее время, поэтому, возможно, это не так такой важный, но любопытный вопрос. - person alockwood05; 05.11.2015

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

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

vs.

link: function(scope, element, attrs) {... //no services allowed
person ScaryBunny    schedule 07.11.2013
comment
Пожалуйста, оставьте комментарий, чтобы объяснить свою точку зрения, когда вы голосуете против ответа. Спасибо - person svassr; 22.11.2013
comment
Я не был противником, но это не совсем правильно, потому что вы все равно можете добавить любую требуемую зависимость в саму директиву, например: module.directive('myDirective', function($window) { etc.... Затем к нему можно получить доступ изнутри функции ссылки. - person Mike Chamberlain; 02.12.2013
comment
Лучшее объяснение разницы в том, что вы можете вводить в функции ссылки, компиляции или контроллера, - это stackoverflow.com/a/14300374/275581. Функция ссылки не использует внедрение зависимостей и передается в точности с указанными выше аргументами. Функция компиляции использует внедрение зависимостей, привязанных к отдельному экземпляру директивы, поэтому у нее есть все глобальные зависимости, а также локальные, такие как $scope. То же самое для контроллера. Сама директива создается более глобально и не получает зависимостей для каждого экземпляра (нет $scope). - person metamatt; 19.06.2014
comment
это кажется явно неверным, поскольку вы можете вводить службы в функцию ссылки - person Code Whisperer; 15.08.2014
comment
Было бы интересно увидеть плункер службы, внедренной в функцию ссылки. - person demisx; 24.02.2015
comment
Этот пример внедряется в директивную функцию, которая доступна для функции link () через область закрытия. Этот plnkr не является примером внедрения сервисов в функцию ссылки как таковую, что невозможно. - person Josh Ribakoff; 13.05.2015
comment
@JoshRibakoff Конечный результат тот же, у вас есть доступ к сервису в функции ссылки. Неважно, объявлено это в аргументах функции или нет. В этом отношении Майк Чемберлен прав. - person Connor Wyatt; 30.07.2015
comment
@ cwyatt1 Я поправлял язык, plnkr не показывает инъекцию в функцию link (), потому что это не функция Angular. Вы можете подумать, что я педантичен, но комментарий metamatts уже описывает многочисленные важные различия между тем, что делает этот plunkr, и тем, что делает инъекция в контроллер. OP спрашивает, в чем различия, и есть различия. - person Josh Ribakoff; 31.07.2015
comment
@scareBunny Это не то, вы тоже можете воспользоваться сервисом. - person Scipion; 14.12.2015

это хороший пример для понимания фаз директивы 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's 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>
person Amin Rahimi    schedule 18.07.2015
comment
Не могли бы вы пояснить, почему этот пример кода поможет понять разницу между link, compile и controller? - person cel sharp; 17.08.2015
comment
знаете ли вы, как директиву required можно ввести в контроллер зависимой директивы? - person alockwood05; 25.09.2015
comment
Пример кода вашего кода: Неперехваченная ошибка: [$ injector: modulerr] Не удалось создать экземпляр модуля myapp из-за: Ошибка: [$ injector: unpr] Неизвестный поставщик: slngStylePrelinkProvider - person rofrol; 08.11.2016

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