Comunicação entre diretivas aninhadas

61

Parece haver algumas maneiras de se comunicar entre diretivas. Digamos que você tenha diretivas aninhadas, nas quais as diretivas internas devem comunicar algo ao externo (por exemplo, foram escolhidas pelo usuário).

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

Até agora eu tenho 5 maneiras de fazer isso

require: diretiva pai

A innerdiretiva pode exigir a outerdiretiva, que pode expor algum método em seu controlador. Então, na innerdefinição

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

E no outercontrolador da diretiva:

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

$emit evento

A innerdiretiva pode $emitum evento ao qual a outerdiretiva possa responder, via $on. Portanto, no innercontrolador da diretiva:

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

e no outercontrolador de diretivas:

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

Executar expressão no escopo pai, via &

O item pode vincular-se a uma expressão no escopo pai e executá-la em um ponto apropriado. O HTML seria como:

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

Portanto, o innercontrolador possui uma função 'innerChoose' que pode ser chamada

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

que chamaria (neste caso) a função 'functionOnOuter' no outerescopo da diretiva:

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

Herança de escopo em escopo não isolado

Dado que estes são controladores aninhados, a herança do escopo pode estar em funcionamento, e a diretiva interna pode simplesmente chamar quaisquer funções na cadeia de escopo, desde que não tenha um escopo isolado). Então, na innerdiretiva:

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

E na outerdiretiva:

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

Por serviço injetado no interior e no exterior

Um serviço pode ser injetado nas duas diretivas, para que eles possam ter acesso direto ao mesmo objeto ou chamar funções para notificar o serviço e talvez até se registrar para serem notificados em um sistema de publicação / publicação. Isso não requer que as diretivas sejam aninhadas.

Pergunta : Quais são os possíveis inconvenientes e vantagens de cada um em relação aos outros?

Michal Charemza
fonte
5
Não acredito que não tenha visto essa pergunta até agora. Agradeço todas as opções que você forneceu. Se você ainda não o fez, já pensou em postar esta pergunta no stackoverflow? Eu esperaria que isso tivesse muito mais tração no stackoverflow.
precisa saber é o seguinte
Consulte esta proposta - softwareengineering.stackexchange.com/questions/344165/…
yellowblood 15/17

Respostas:

7

Minha preferência é definir um &atributo no escopo da diretiva principalmente porque vejo a scope: {}definição de uma diretiva como sua API. É muito mais fácil olhar para uma definição de atributo de escopo para ver quais informações a diretiva precisa para funcionar corretamente do que para vasculhar as funções de link e controlador em busca $emitde eventos, funções de escopo herdadas ou funções usadas nos controladores injetados.

Jeff Swensen
fonte
1

Minha opinião:

Os serviços são a maneira preferida de compartilhar comportamentos / dados entre módulos / diretivas / controladores. Diretivas são coisas isoladas que podem ser aninhadas ou não. Os controladores devem permanecer o máximo possível de um modelo de exibição, idealmente, nenhuma lógica de negócios deve acabar aí.

Assim:

Quando você começa a conectá-los acessando as funções de escopo pai, acho que você corre o risco de acoplá-las com muita força e tornar todo o aplicativo ilegível e os componentes não reutilizáveis. Ao dissociar esses dados ou comportamentos compartilhados em um serviço, você tem o benefício de reutilizar as diretivas inteiras com dados / comportamentos diferentes, até mesmo determinando o serviço a ser usado no tempo de execução. Qual é o objetivo da injeção de dependência.

RobbyD
fonte