Komunikacja między zagnieżdżonymi dyrektywami

61

Wydaje się, że istnieje wiele sposobów komunikowania się między dyrektywami. Powiedzmy, że masz zagnieżdżone dyrektywy, w których wewnętrzne dyrektywy muszą komunikować coś z zewnętrznymi (np. Zostało wybrane przez użytkownika).

<outer>
  <inner></inner>
  <inner></inner>
</outer>

Do tej pory mam 5 sposobów na zrobienie tego

require: dyrektywa nadrzędna

innerDyrektywa może wymagać outerdyrektywę, która może narazić jakiś sposób na jego sterownika. Więc w innerdefinicji

require: '^outer',
link: function(scope, iElement, iAttrs, outerController) {
   // This can be passed to ng-click in the template
   $scope.chosen = function() {
     outerController.chosen(something);
   }
}

A w outerkontrolerze dyrektywy:

controller: function($scope) {
   this.chosen = function(something) {
   }
}

$emit zdarzenie

innerDyrektywy może $emitzdarzenie, którego outerdyrektywa może odpowiedzieć, poprzez $on. Zatem w innerkontrolerze dyrektywy:

controller: function($scope) {
  $scope.chosen = function() {
    $scope.$emit('inner::chosen', something);
  }
}

a w outerdyrektywach kontroler:

controller: function($scope) {
  $scope.$on('inner::chosen, function(e, data) {
  }
}

Wykonaj wyrażenie w zakresie nadrzędnym za pośrednictwem &

Element może powiązać się z wyrażeniem w zakresie nadrzędnym i wykonać go w odpowiednim punkcie. HTML wyglądałby tak:

<outer>
  <inner inner-choose="functionOnOuter(item)"></inner>
  <inner inner-choose="functionOnOuter(item)"></inner>
</outer>

Tak więc innerkontroler ma funkcję „InternalChoose”, którą może wywołać

scope: {
  'innerChoose': '&'
},
controller: function() {
  $scope.click = function() {
    $scope.innerChoose({item:something});
  }
}

która wywołałaby (w tym przypadku) funkcję „functionOnOuter” w zakresie outerdyrektywy:

controller: function($scope) {
  $scope.functionOnOuter = function(item) {
  }
}

Dziedziczenie zakresu w zakresie nieizolowanym

Biorąc pod uwagę, że są to kontrolery zagnieżdżone, dziedziczenie zakresu może działać, a wewnętrzna dyrektywa może po prostu wywoływać dowolne funkcje w łańcuchu zasięgu, o ile nie ma izolowanego zakresu). Tak więc w innerdyrektywie:

// scope: anything but a hash {}
controller: function() {
  $scope.click = function() {
    $scope.functionOnOuter(something);
  }
}

A w outerdyrektywie:

controller: function($scope) {
  $scope.functionOnOuter = function(item) {
  }
}

Przez usługę wstrzykuje się zarówno wewnętrzną, jak i zewnętrzną

Usługę można wprowadzić do obu dyrektyw, aby mogły mieć bezpośredni dostęp do tego samego obiektu lub wywoływać funkcje w celu powiadomienia usługi, a może nawet zarejestrować się, aby otrzymać powiadomienie, w systemie pub / sub. Nie wymaga to zagnieżdżania dyrektyw.

Pytanie : Jakie są potencjalne wady i zalety każdego z nich?

Michał Charemza
źródło
5
Nie mogę uwierzyć, że nie widziałem tego pytania wcześniej. Doceniam wszystkie opcje, które podałeś. Jeśli jeszcze tego nie zrobiłeś, czy pomyślałeś o opublikowaniu tego pytania na stackoverflow? Spodziewałbym się, że przy przepełnieniu stosu uzyska znacznie lepszą przyczepność.
Mike Barlow - BarDev
Proszę zobaczyć tę propozycję - softwareengineering.stackexchange.com/questions/344165/…
yellowblood

Odpowiedzi:

7

Preferuję definiowanie &atrybutu w zakresie dyrektywy przede wszystkim dlatego, że uważam scope: {}definicję dyrektywy za jej interfejs API. O wiele łatwiej jest spojrzeć na definicję atrybutu zasięgu, aby zobaczyć, jakie informacje musi funkcjonować dyrektywa, niż przeszukać funkcje łącza i kontrolera pod kątem $emitzdarzeń, dziedziczonych funkcji zakresu lub funkcji używanych w kontrolerach wstrzykiwanych.

Jeff Swensen
źródło
1

Moja opinia:

Usługi są preferowanym sposobem udostępniania zachowania / danych między modułami / dyrektywami / kontrolerami. Dyrektywy to pojedyncze rzeczy, które można zagnieżdżać lub nie. Administratorzy powinni trzymać się modelu wyświetlania tak bardzo, jak to tylko możliwe, idealnie, gdyby nie logika biznesowa.

Więc:

Kiedy zaczynasz je łączyć ze sobą, uzyskując dostęp do funkcji zakresu nadrzędnego, myślę, że ryzykujesz ich zbyt mocnym połączeniem i sprawia, że ​​cała aplikacja jest nieczytelna, a części nie można ponownie użyć. Po odsprzęgnięciu współużytkowanych danych lub zachowania w usłudze zyskujesz możliwość ponownego wykorzystania całych dyrektyw z różnymi danymi / zachowaniem, nawet określając usługę, która ma być używana w czasie wykonywania. O to właśnie chodzi w iniekcji zależności.

RobbyD
źródło