Link vs kompilacja vs kontroler


529

Podczas tworzenia dyrektywy można wstawić kod do kompilatora, funkcji łącza lub kontrolera.

W dokumentach wyjaśniają, że:

  • funkcje kompilacji i łączenia są używane w różnych fazach cyklu kątowego
  • kontrolery są współużytkowane między dyrektywami

Jednak dla mnie nie jest jasne, jaki kod powinien iść gdzie.

Np .: Czy mogę tworzyć funkcje w kompilacji i mieć je dołączone do zakresu w łączu, czy tylko dołączać funkcje do zakresu w kontrolerze?

W jaki sposób kontrolery są dzielone między dyrektywy, jeśli każda dyrektywa może mieć swój własny kontroler? Czy kontrolery są naprawdę współużytkowane, czy to tylko właściwości zakresu?



Być może bardziej wszechstronny przegląd funkcji dyrektywy: Dyrektywy kątowe - kiedy używać kompilacji, kontrolera, pre-link i post-link .
Izhaki,

1
Napisałem post ze schematem cyklu życia dyrektywy (faza tworzenia). Może to komuś pomaga: filimanjaro.com/2014/…
średni Joe

Odpowiedzi:


470

Kompiluj:

Na tym etapie Angular kompiluje twoją dyrektywę. Ta funkcja kompilacji jest wywoływana tylko raz dla każdego odwołania do danej dyrektywy. Załóżmy na przykład, że używasz dyrektywy ng-repeat. ng-repeat będzie musiał wyszukać element, do którego jest dołączony, wyodrębnić fragment HTML, do którego jest dołączony, i utworzyć funkcję szablonu.

Jeśli użyłeś HandleBars, szablonów podkreślenia lub równoważnych, to tak jak kompilowanie ich szablonów w celu wyodrębnienia funkcji szablonu. Do tej funkcji szablonu przekazujesz dane, a zwracaną wartością tej funkcji jest html z danymi we właściwych miejscach.

Faza kompilacji to etap w Angular, który zwraca funkcję szablonu. Ta funkcja szablonu w układzie kątowym nazywa się funkcją łączenia.

Faza łączenia:

Faza łączenia to miejsce, w którym dołączasz dane ($ scope) do funkcji łączenia i powinna ona zwrócić ci połączony HTML. Ponieważ dyrektywa określa również, gdzie idzie ten HTML lub co się zmienia, warto już iść. Jest to funkcja, w której chcesz wprowadzić zmiany w połączonym html, tj. Html, który już ma dołączone dane. W angular, jeśli piszesz kod w funkcji łączenia, jest to zazwyczaj funkcja post-link (domyślnie). Jest to rodzaj wywołania zwrotnego, które jest wywoływane po powiązaniu danych z szablonem przez funkcję łączenia.

Kontroler :

Kontroler to miejsce, w którym wprowadzasz logikę specyficzną dla dyrektywy. Ta logika może również przejść do funkcji łączenia, ale wtedy musiałbyś umieścić tę logikę w zakresie, aby uczynić ją „współdzieloną”. Problem polega na tym, że powodowałbyś wówczas uszkodzenie zakresu za pomocą dyrektyw, co nie jest tak naprawdę oczekiwanym. Więc jaka jest alternatywa, jeśli dwie dyrektywy chcą ze sobą rozmawiać / współpracować ze sobą? Oczywiście można umieścić całą tę logikę w usłudze, a następnie uzależnić obie te dyrektywy od tej usługi, ale to po prostu wprowadza jeszcze jedną zależność. Alternatywą jest zapewnienie kontrolera dla tego zakresu (zwykle izolować zakres?), A następnie kontroler ten jest wprowadzany do innej dyrektywy, gdy ta dyrektywa „wymaga” drugiej.


67
Aby to wyjaśnić: kompilacja kompiluje szablon, który będzie używany na całej stronie. Linker jest powiązany z każdą instancją. Dobrze? Kontroler następnie działa między instancjami.
Zlatko

4
@CMCDragonkai dla każdej controllerfunkcji dyrektywy jest wykonywana po kompilacji, ale wcześniej pre-link w lokalnej gałęzi drzewa DOM. Również controlleri pre-linkfunkcje są wykonywane przez lokalny oddział DOM w odgórny sposób. Następnie post-linkjest wykonywany w sposób oddolny .
Artem Platonov

9
To tylko bałagan, jeśli go nie rozumiesz. Jest powód, aby robić to, co robi.
demisx

3
To jest prawidłowa odpowiedź techniczna, jednak wciąż mam pytania, kiedy powinienem użyć funkcji link.
Nicholas Marshall

2
Czy powinniśmy używać controllerzamiast linkwszędzie? Aby nie musiałem zmieniać kodu w przyszłości, jeśli trzeba udostępnić metodę lub wprowadzić logikę ?. Czy są jakieś pułapki w używaniu przez controllercały czas zamiast linku?
JPS

99

Chciałem również dodać, co ma do powiedzenia książka O'Reily AngularJS zespołu Google:

Kontroler - Utwórz kontroler, który publikuje interfejs API do komunikacji między dyrektywami. Dobrym przykładem jest komunikacja między dyrektywą a dyrektywą

Link - Programowo zmodyfikuj powstałe instancje elementu DOM, dodaj detektory zdarzeń i skonfiguruj powiązanie danych.

Kompiluj - programowo zmodyfikuj szablon DOM dla funkcji w różnych kopiach dyrektywy, tak jak w przypadku ng-repeat. Twoja funkcja kompilacji może również zwracać funkcje łącza, aby zmodyfikować powstałe instancje elementu.


Twój link thinkster.io nie może być oglądany bez płacenia. Nie mój link, ale być może jest to bardziej odpowiednie: toddmotto.com/directive-to-directive-communication-withrequire
R. van Twisk

51

A directivepozwala na poszerzenie słownictwa HTML w deklaratywny sposób do budowania komponentów internetowych. ng-appAtrybut jest dyrektywa, tak jest ng-controlleri wszyscy ng- prefixed attributes. Dyrektywy mogą być attributes, tagslub nawet class names, comments.

Jak powstają dyrektywy ( compilationi instantiation)

Kompilacja: użyjemy tej compilefunkcji zarówno manipulatedla DOM, zanim zostanie on zrenderowany, jak i zwrócimy linkfunkcję (która obsłuży dla nas linkowanie). Jest to również miejsce do umieszczenia wszelkich metod, które muszą być udostępnione wszystkim instancesz tej dyrektywy.

link: użyjemy tej linkfunkcji do zarejestrowania wszystkich detektorów w określonym elemencie DOM (sklonowanym z szablonu) i skonfigurowania naszych powiązań ze stroną.

Jeśli ustawione w compile() funkcji, byłyby ustawione tylko raz (co często jest tym, czego chcesz). Jeśli ustawione w link()funkcji, byłyby ustawione za każdym razem, gdy element HTML jest powiązany z danymi w obiekcie.

<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){

     }
   };
});

Compilefunkcja zwraca funkcję prei postlink. W funkcji wstępnego linku mamy szablon instancji, a także zakres z controller, ale szablon nie jest powiązany z zakresem i nadal nie zawiera treści zawartej w transkluzji.

Postfunkcja link to miejsce, w którym link do strony to ostatnia funkcja do wykonania. Teraz transclusionjest gotowe,the template is linked to a scope , i view will update with data bound values after the next digest cycle. Ta linkopcja jest tylko skrótem do konfiguracji post-linkfunkcji.

kontroler: dyrektywy można przekazać do innej fazy łączenia / kompilacji dyrektywy. Może być wprowadzony do innych dyrektyw jako środek do wykorzystania w komunikacji między dyrektywami.

Musisz podać nazwę wymaganej dyrektywy - powinna ona być powiązana z tym samym elementem lub jego rodzicem. Nazwę można poprzedzić:

?  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.

Użyj nawiasu kwadratowego, [‘directive1′, ‘directive2′, ‘directive3′]aby wymagać kontrolera wielu dyrektyw.

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
wspomniałeś, że pokazałeś, jak wprowadzić parentDirectiveCtrl do kontrolera dziecka ... w tym przykładzie dziecko nie ma kontrolera, a raczej funkcję linku ... Obecnie nie utknąłem w tej kwestii, więc może nie być tak ważne, ale ciekawe pytanie.
alockwood05

13

Ponadto dobrym powodem do użycia funkcji kontroler vs. link (ponieważ oba mają dostęp do zakresu, elementu i atrybutów) jest to, że można przekazać dowolną dostępną usługę lub zależność do kontrolera (i w dowolnej kolejności), podczas gdy nie można tego zrobić za pomocą funkcji link. Zwróć uwagę na różne podpisy:

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

vs.

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

2
Zostaw komentarz, aby wyjaśnić swój punkt, gdy głosujesz za odpowiedzią. Dzięki
svassr

53
Nie byłem downvoter, ale nie jest to do końca słuszne, ponieważ nadal możesz wprowadzić dowolną wymaganą zależność do samej dyrektywy, np module.directive('myDirective', function($window) { etc.... : . Następnie można uzyskać do niego dostęp z poziomu funkcji łącza.
Mike Chamberlain,

1
wydaje się to wprost niepoprawne, ponieważ można wstrzykiwać usługi do funkcji łącza
Code Whisperer

1
@JoshRibakoff Wynik końcowy jest taki sam, masz dostęp do usługi w funkcji link. Nie ma znaczenia, czy jest zadeklarowana w argumentach funkcji, czy nie. Pod tym względem Mike Chamberlain ma rację
Connor Wyatt

1
@ cwyatt1 Poprawiałem język, plnkr nie pokazuje wstrzykiwania do funkcji link (), ponieważ nie jest to cecha Angulara. Może ci się wydawać, że jestem pedantyczny, ale komentarz metamat już pokazuje wiele ważnych różnic między tym, co robi ten plunkr, a tym, co robi wstrzykiwanie do kontrolera. OP pyta, jakie są różnice i są różnice.
Josh Ribakoff

10

jest to dobra próbka do zrozumienia faz dyrektywy 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
Czy mógłbyś wyjaśnić, dlaczego ten przykładowy kod pomógłby zrozumieć różnicę między link, compilea controller?
cel sharp

czy wiesz, w jaki sposób requiremożna wprowadzić dyrektywę d do kontrolera zależnej dyrektywy?
alockwood05

Jesteś codepen przykład: Uncaught Błąd: [$ injector: modulerr] Nie udało się utworzyć instancji modułu myapp z powodu: Błąd: [$ injector: unpr] Nieznany dostawca: slngStylePrelinkProvider
rofrol

7
  • kompilacja : używana, gdy potrzebujemy zmodyfikować szablon dyrektywy, np. dodać nowe wyrażenie, dołączyć kolejną dyrektywę wewnątrz tej dyrektywy
  • kontroler : używany, gdy potrzebujemy udostępnić / ponownie wykorzystać dane zakresu $
  • link : jest to funkcja, która jest używana, gdy potrzebujemy dołączyć moduł obsługi zdarzeń lub manipulować DOM.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.