Посилання проти компіляції проти контролера


529

Коли ви створюєте директиву, ви можете помістити код у компілятор, функцію зв'язку або контролер.

У документах вони пояснюють, що:

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

Однак для мене незрозуміло, який саме код повинен куди піти.

Напр .: Чи можу я створити функції у компіляції та приєднати їх до області посилань або лише приєднати функції до області в контролері?

Як розподіляються контролери між директивами, якщо кожна директива може мати власний контролер? Чи дійсно контролери спільні чи це лише властивості області застосування?




1
Я написав пост із діаграмою життєвого циклу директиви (фаза створення). Можливо, це комусь допоможе: filimanjaro.com/2014/…
середній Джо

Відповіді:


470

Збірка:

Це етап, коли Angular насправді складає вашу директиву. Ця функція компіляції викликається лише один раз для кожного посилання на дану директиву. Наприклад, скажіть, що ви використовуєте директиву ng-repeat. ng-повтор повинен буде шукати елемент, до якого він приєднаний, витягнути фрагмент html, до якого він додається, та створити функцію шаблону.

Якщо ви використовували HandleBars, підкреслюють шаблони або подібні, подібні до складання їх шаблонів для вилучення функції шаблону. У цю функцію шаблону ви передаєте дані, а зворотним значенням цієї функції є html з даними в потрібних місцях.

Етап компіляції - це крок у куті, який повертає функцію шаблону. Ця функція шаблону в кутовій називається функцією зв’язку.

Фаза зв'язування:

На етапі зв’язування ви додаєте дані ($ область) до функції зв’язку, і вона повинна повернути вам пов'язаний html. Оскільки в директиві також зазначено, куди йде цей html або що він змінюється, це вже добре піти. Це функція, в якій потрібно внести зміни до пов'язаного html, тобто html, до якого вже додані дані. У кутовому випадку, якщо ви пишете код у функції зв’язування, це його функція, як правило, пост-посилання (за замовчуванням). Це свого роду зворотний виклик, який викликається після того, як функція зв'язування зв'язала дані з шаблоном.

Контролер:

Контролер - це місце, де ви вводите певну логіку, визначену в директиві. Ця логіка може входити і у функцію зв’язування, але тоді вам доведеться поставити цю логіку на область, щоб зробити її "доступною для доступу". Проблема з цим полягає в тому, що ви згодом зіпсуєте сферу застосування своїх директив, що насправді не те, що очікується. То яка альтернатива, якщо дві Директиви хочуть поговорити між собою / співпрацювати? Звичайно, ви можете вкласти всю цю логіку в службу, а потім зробити обидві ці директиви залежними від цієї послуги, але це просто приводить до ще однієї залежності. Альтернативою є надання контролера для цієї області (як правило, ізолювати область?), А потім цей контролер вводиться в іншу директиву, коли ця директива "вимагає" іншу.


67
Для уточнення: компілювати компілює шаблон, який буде використовуватися на всій сторінці. Linker прив’язується до кожного екземпляра. Правильно? Потім контролер працює між екземплярами.
Златко

4
@CMCDragonkai для кожної controllerфункції директиви виконується після компіляції, але раніше pre-link в локальній гілці дерева DOM. Також controllerі pre-linkфункції виконуються обході місцеве відділення DOM в низхідному порядку. Після цього post-linkвиконується способом знизу вгору .
Артем Платонов

9
Це лише безлад, якщо ти цього не розумієш. Для цього є причина робити те, що робить.
demisx

3
Це правильна технічна відповідь, однак у мене все ще залишаються питання щодо того, коли мені слід використовувати функцію посилання.
Ніколас Маршалл

2
Чи ми будемо використовувати controllerзамість них linkскрізь? Так що мені не потрібно міняти код у майбутньому, якщо методом потрібно ділитися загальним способом або вводити певну логіку ?. Чи є якісь підводні камені у використанні controllerвесь час замість посилання?
JPS

99

Я хотів би додати також те, що має сказати книга O'Reily AngularJS від команди Google:

Controller - Створіть контролер, який публікує API для зв'язку між директивами. Хороший приклад - Директива до Директиви зв'язку

Посилання - Програмно змінювати отримані екземпляри елементів DOM, додавати слухачів подій та встановлювати прив'язку даних.

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


Ваш посилання thinkter.io не можна переглядати без оплати. Не моє посилання, але, можливо, це більше підходить: toddmotto.com/directive-to-directive-communication-with-require
R. van Twisk

51

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функція посилання - це те, де пост-посилання є останньою функцією, яку потрібно виконати. Тепер 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
    }
  }
});

1
Ви згадали, що ви показали, як отримати parentDirectiveCtrl в дитячий контролер ... у цьому прикладі дитина не має контролера, а швидше функцію зв'язку ... Я зараз не зациклювався на цьому питанні, тому це може бути не так настільки важливе, але цікаве питання.
alockwood05

13

Крім того, вагомий привід використовувати функцію контролер та зв’язок (оскільки вони обидва мають доступ до області, елемента та attrs) тому, що ви можете передати будь-яку доступну службу чи залежність до контролера (і в будь-якому порядку), тоді як цього не можна робити за допомогою функції зв’язку. Помітьте різні підписи:

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

vs.

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

2
Будь ласка, залиште коментар, щоб пояснити свою точку, коли ви зволікаєте відповідь. Спасибі
svassr

53
Я не був downvoter, але це не зовсім правильно , тому що ви все ще можете надати будь-яку необхідну залежність в самій директиви, наприклад: module.directive('myDirective', function($window) { etc.... Потім це можна отримати з внутрішньої функції посилання.
Майк Чемберлен

1
це здається прямо неправильним, оскільки ви можете вводити служби у функцію посилання
Код Шепірера

1
@JoshRibakoff Кінцевий результат такий же, у вас є доступ до служби у функції посилання. Не має значення, заявлено це в аргументах функції чи ні. У цьому плані Майк Чемберлен правильний
Коннор Віатт

1
@ cwyatt1 Я виправляв мовлення, plnkr не показує введення в функцію link (), оскільки це не є властивістю Angular. Ви можете подумати, що я буду педантичним, але коментар метаматтів вже окреслює численні важливі відмінності між тим, що робить цей plunkr, і тим, що робить ін'єкція контролеру. ОП запитує, в чому полягають відмінності, а є відмінності.
Джош Рібакофф

10

це хороший зразок для розуміння фаз директив 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>

4
Чи не могли б ви уточнити , чому цей приклад коду допоможе зрозуміти різницю між link, compileі controller?
чел гострий

чи знаєте ви, як required-директива може бути введена в контролер залежної директиви?
alockwood05

Приклад кодування: Uncaught Error: [$ injector: modulerr] Не вдалося інстанціювати модуль myapp через: Помилка: [$ injector: unpr] Невідомий постачальник: slngStylePrelinkProvider
rofrol

7
  • compile : використовується, коли нам потрібно змінити шаблон директиви, як-от додати новий вираз, додати ще одну директиву всередині цієї директиви
  • Контролер : використовується, коли нам потрібно ділитися / повторно використовувати дані про область $
  • посилання : це функція, яка використовується, коли нам потрібно приєднати обробник подій або маніпулювати DOM.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.