Angular JS: Jaka jest potrzeba funkcji link dyrektywy, skoro mieliśmy już kontroler dyrektywy z zakresem?

199

Muszę wykonać pewne operacje na zakresie i szablonie. Wydaje się, że mogę to zrobić w linkfunkcji lub controllerfunkcji (ponieważ oba mają dostęp do zakresu).

Kiedy jest tak, że muszę korzystać z linkfunkcji, a nie ze sterownika?

angular.module('myApp').directive('abc', function($timeout) {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: true,
        link: function(scope, elem, attr) { /* link function */ },
        controller: function($scope, $element) { /* controller function */ }
    };
}

Rozumiem również, że linkjest to świat nie kątowy. Więc mogę używać $watch, $digesti $apply.

Jakie znaczenie ma linkfunkcja, kiedy mieliśmy już kontroler?

Yugal Jindle
źródło
9
Co masz na myśli przez „ Ponadto, rozumiem, że związek jest non-kanciasty świat. Tak, mogę używać $watch, $digesti $apply. ”?
musically_ut
2
Wewnątrz linknie widzimy żadnej magii kątowej. tzn. brak powiązań dwukierunkowych itp. Wystarczy, że mamy dostępne api kątownika.
Yugal Jindle

Odpowiedzi:

299

Po moim początkowym walka z linki controllerfunkcji czytania i sporo o nich, myślę, że teraz mam odpowiedź.

Najpierw zrozumiemy ,

Jak w skrócie działają dyrektywy kątowe:

  • Zaczynamy od szablonu (jako ciąg lub załadowany do ciągu)

    var templateString = '<div my-directive>{{5 + 10}}</div>';

  • Teraz templateStringjest to owinięte jako element kątowy

    var el = angular.element(templateString);

  • Dzięki el, teraz skompilować je $compileodzyskać łącza funkcję.

    var l = $compile(el)

    Oto co się dzieje

    • $compile przechodzi przez cały szablon i zbiera wszystkie rozpoznane dyrektywy.
    • Wszystkie wykryte dyrektywy są kompilowane rekurencyjnie, a ich linkfunkcje są gromadzone.
    • Następnie wszystkie linkfunkcje są pakowane w nową linkfunkcję i zwracane jako l.
  • Wreszcie, zapewniamy scopefunkcję tej funkcji l(link), która dodatkowo wykonuje zawinięte funkcje linku wraz z tą scopei odpowiadającymi jej elementami.

    l(scope)

  • Dodaje to templatejako nowy węzeł do DOMi wywołuje, controllerktóry dodaje swoje zegarki do zakresu współdzielonego z szablonem w DOM.

wprowadź opis zdjęcia tutaj

Porównanie kompilacji vs linku vs kontrolera :

  • Każda dyrektywa jest kompilowana tylko raz, a funkcja link zostaje zachowana do ponownego użycia. Dlatego jeśli coś dotyczy wszystkich instancji dyrektywy, należy ją wykonać w ramach compilefunkcji dyrektywy .

  • Teraz po kompilacji mamy linkfunkcję, która jest wykonywana podczas dołączania szablonu do DOM . Dlatego wykonujemy wszystko, co jest specyficzne dla każdej instancji dyrektywy. Na przykład: dołączanie zdarzeń , mutowanie szablonu na podstawie zakresu itp.

  • Wreszcie, kontroler ma być dostępny do działania i reagowania, podczas gdy dyrektywa działa na DOM(po przywiązaniu). W związku z tym:

    (1) Po skonfigurowaniu widoku [ V ] (tj. Szablonu) z linkiem. $scopejest naszym [ M ] i $controllernaszym [ C ] w MVC

    (2) Skorzystaj z 2-kierunkowego wiązania z $ scope , ustawiając zegarki.

    (3) $scopeoczekuje się, że zegarki zostaną dodane do kontrolera, ponieważ właśnie to ogląda szablon w czasie wykonywania.

    (4) Wreszcie, controllersłuży również do komunikowania się między powiązanymi dyrektywami. (Jak myTabsprzykład w https://docs.angularjs.org/guide/directive )

    (5) To prawda, że ​​moglibyśmy zrobić to wszystko również w linkfunkcji, ale chodzi o rozdzielenie obaw .

Dlatego wreszcie mamy następujące, które idealnie pasują do wszystkich elementów:

wprowadź opis zdjęcia tutaj

Yugal Jindle
źródło
5
Uważam również, że ten artykuł jest przydatny do zrozumienia kolejności wykonywania tutaj: drobiazgowość funkcji kompilacji i łączenia w dyrektywach AngularJS
BobbyA
4
Świetne wyjaśnienie. Chciałbym wspomnieć, że kontroler jest wywoływany przed funkcją link.
jsbisht
38
kontroler jest wykonywany przed łączem
Royi Namir,
10
Denerwuje mnie to, że Przepełnienie stosu wymaga, aby zmiany zawierały co najmniej 6 znaków, a tym samym nie pozwalają mi na poprawienie pisowni „Let's” w tej odpowiedzi.
user1886323,
79

Dlaczego kontrolery są potrzebne

Różnica pomiędzy linki controllerpojawia się, gdy chcesz zagnieżdżać dyrektywy w DOM i wystawiać funkcje API z dyrektywy nadrzędnej na zagnieżdżone.

Z dokumentów :

Najlepsza praktyka: używaj kontrolera, gdy chcesz udostępnić API innym dyrektywom. W przeciwnym razie użyj linku.

Powiedz, że chcesz mieć dwie dyrektywy my-formi my-text-inputchcesz, aby my-text-inputdyrektywa pojawiła się tylko w środku my-formi nigdzie indziej.

W takim przypadku, można powiedzieć podczas definiowania dyrektywę my-text-inputże wymaga kontrolera z parentelementu DOM przy użyciu wymaga argumentu, tak: require: '^myForm'. Teraz kontroler z elementu nadrzędnego przejdzie injecteddo linkfunkcji jako czwarty argument za nim $scope, element, attributes. Możesz wywoływać funkcje na tym kontrolerze i komunikować się z dyrektywą nadrzędną.

Ponadto, jeśli taki kontroler nie zostanie znaleziony, zostanie zgłoszony błąd.

Po co w ogóle korzystać z linku

Nie ma potrzeby używania tej linkfunkcji, jeśli się ją definiuje, controllerponieważ $scopejest ona dostępna w controller. Ponadto, definiując jedno linki drugie controller, należy uważać na kolejność wywoływania dwóch ( controllerjest wykonywana wcześniej).

Jednak, zgodnie ze sposobem Angular , większość manipulacji DOM i 2-kierunkowe wiązanie $watchersodbywa się zwykle w linkfunkcji, podczas gdy API dla dzieci i $scopemanipulowanie odbywa się w controller. Nie jest to trudna i szybka reguła, ale spowoduje to, że kod będzie bardziej modułowy i pomoże w rozdzieleniu problemów (kontroler utrzyma directivestan, a linkfunkcja zachowa DOM+ powiązania zewnętrzne).

muzycznie
źródło
To wspaniale. Czy możesz mi pomóc w drugiej części pytania?
Yugal Jindle
Mam na myśli, ponieważ mieliśmy kontroler, który mógłby zostać wykorzystany do komunikacji z innymi dyrektywami. Czego więc potrzebowaliśmy link?
Yugal Jindle
1
Twoja odpowiedź w jakiś sposób nie odpowiada na rzeczywiste pytanie.
Yugal Jindle
1
Czy występują jakieś problemy, gdy definiujemy controller? Dlaczego chcę wymyślić zupełnie nową funkcję, aby uniknąć definiowania kontrolera?
Yugal Jindle
1
Wygląda na to, że link @scalaGirl s już nie działa
Minato
17

controllerFunkcja / przedmiot stanowi abstrakcji modelu-view kontroler (MVC). Chociaż nie ma nic nowego do napisania o MVC, nadal jest to najważniejsza zaleta kąta: podziel obawy na mniejsze części. I to wszystko, nic więcej, więc jeśli trzeba reagować na Modelzmiany pochodzące z jest właściwa osoba zrobić to zadanie.ViewController

Historia o linkfunkcji jest inna, pochodzi z innej perspektywy niż MVC. Jest to naprawdę niezbędne, gdy chcemy przekroczyć granice controller/model/view (szablonu) .

Zacznijmy od parametrów, które są przekazywane do linkfunkcji:

function link(scope, element, attrs) {
  • zakres jest obiektem zakresu kątowego.
  • element to element zawinięty w jqLite, który jest zgodny z tą dyrektywą.
  • attrs to obiekt ze znormalizowanymi nazwami atrybutów i odpowiadającymi im wartościami.

Aby umieścić linkw kontekście, powinniśmy wspomnieć, że wszystkie dyrektywy przechodzą przez następujące kroki procesu inicjalizacji: Kompiluj , Łącz . Fragment książki Brada Greena i Shyama Seshadri Angular JS :

Faza kompilacji (siostra linku, wspomnijmy tutaj, aby uzyskać wyraźny obraz):

W tej fazie Angular prowadzi DOM w celu zidentyfikowania wszystkich zarejestrowanych dyrektyw w szablonie. Dla każdej dyrektywy następnie przekształca DOM w oparciu o reguły dyrektywy (szablon, zamień, przetaczaj itd.) I wywołuje funkcję kompilacji, jeśli istnieje. Wynikiem jest skompilowana funkcja szablonu,

Faza łącza :

Aby widok był dynamiczny, Angular uruchamia następnie funkcję link dla każdej dyrektywy. Funkcje łączenia zwykle tworzą detektory w DOM lub modelu. Słuchacze ci utrzymują synchronizację widoku i modelu.

Miły przykład korzystania z nich linkmożna znaleźć tutaj: Tworzenie niestandardowych dyrektyw . Zobacz przykład: Tworzenie dyrektywy, która manipuluje DOM , która wstawia na stronie „datę i godzinę”, odświeżana co sekundę.

Tylko bardzo krótki fragment z tego bogatego źródła powyżej, pokazujący prawdziwą manipulację za pomocą DOM. Istnieje funkcja przechwycona do usługi $ timeout, a także jest usuwana w wywołaniu destruktora, aby uniknąć wycieków pamięci

.directive('myCurrentTime', function($timeout, dateFilter) {

 function link(scope, element, attrs) {

 ...

 // the not MVC job must be done
 function updateTime() {
   element.text(dateFilter(new Date(), format)); // here we are manipulating the DOM
 }

 function scheduleUpdate() {
   // save the timeoutId for canceling
   timeoutId = $timeout(function() {
     updateTime(); // update DOM
     scheduleUpdate(); // schedule the next update
   }, 1000);
 }

 element.on('$destroy', function() {
   $timeout.cancel(timeoutId);
 });

 ...
Radim Köhler
źródło
3
Wygląda na to, że porównałeś compileri link. linkcontroller
Pytają,
Rozszerzyłem odpowiedź, aby opisać nawet kontroler bardziej szczegółowo. Teraz koncepcje controllervs linkpowinny być jaśniejsze ...
Radim Köhler,
1
Mogę poszukać wyjaśnienia. Ale wydaje się tam trochę rozmazane. Byłoby wspaniale, gdyby ktoś z samego zespołu kątowego mógł za to mówić, przewidując, dokąd go widzi - do linklub controller.
Yugal Jindle
1
To jedyna część, którą chcę zrozumieć (kiedy to nie wystarczy?). Plus, mam wszystkie zalety kątowania controlleri linkjest względnie brzydki. Zespół Angular musi mieć ku temu dobry powód, a nie tylko opcję.
Yugal Jindle
1
Pytanie: Kiedy kontroler jest niewystarczający? Odp .: Gdy potrzebujesz doświadczenia poza Angularem, takiego jak użycie wtyczki JQuery lub użycie funkcji JQlite, jak wspomniano w dokumencie ( docs.angularjs.org/api/ng/function/angular.element:) , wtedy potrzebujesz link
Hasteq,