Comunicación entre directivas anidadas

61

Parece que hay bastantes formas de comunicación entre directivas. Supongamos que tiene directivas anidadas, donde las directivas internas deben comunicar algo a las externas (por ejemplo, ha sido elegido por el usuario).

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

Hasta ahora tengo 5 formas de hacer esto

require: directiva de padres

La innerdirectiva puede requerir la outerdirectiva, que puede exponer algún método en su controlador. Entonces en la innerdefinición

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

Y en el outercontrolador de la directiva:

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

$emit evento

La innerdirectiva puede $emitun evento, al que la outerdirectiva puede responder, a través de $on. Entonces, en el innercontrolador de la directiva:

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

y en el outercontrolador de directivas:

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

Ejecute la expresión en el ámbito primario, a través de &

El elemento puede vincularse a una expresión en el ámbito primario y ejecutarlo en un punto apropiado. El HTML sería como:

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

Entonces el innercontrolador tiene una función 'innerChoose' a la que puede llamar

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

que llamaría (en este caso) la función 'functionOnOuter' en el outeralcance de la directiva:

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

Herencia de alcance en alcance no aislado

Dado que estos son controladores anidados, la herencia del alcance puede estar en funcionamiento, y la directiva interna puede llamar a cualquier función en la cadena del alcance, siempre que no tenga un alcance aislado). Entonces en la innerdirectiva:

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

Y en la outerdirectiva:

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

Por servicio inyectado en interior y exterior

Se puede inyectar un servicio en ambas directivas, para que puedan tener acceso directo al mismo objeto, o llamar a funciones para notificar el servicio, y tal vez incluso registrarse para recibir una notificación, en un sistema pub / subsistema. Esto no requiere que las directivas estén anidadas.

Pregunta : ¿Cuáles son los posibles inconvenientes y ventajas de cada uno sobre los demás?

Michal Charemza
fuente
55
No puedo creer que no haya visto esta pregunta antes. Agradezco todas las opciones que proporcionó. Si aún no lo ha hecho, ¿ha pensado publicar esta pregunta en stackoverflow? Esperaría que obtuviera mucha más tracción en stackoverflow.
Mike Barlow - BarDev
Consulte esta propuesta: softwareengineering.stackexchange.com/questions/344165/…
yellowblood

Respuestas:

7

Prefiero definir un &atributo en el ámbito de la directiva principalmente porque veo la scope: {}definición de una directiva como su API. Es mucho más fácil mirar una definición de atributo de alcance para ver qué información necesita la directiva para funcionar correctamente que para rastrear el enlace y las funciones del controlador para $emit'd eventos, funciones de alcance heredadas o funciones utilizadas dentro de los controladores inyectados.

Jeff Swensen
fuente
1

Mi opinión:

Los servicios son la forma preferida de compartir comportamiento / datos entre módulos / directivas / controladores. Las directivas son cosas aisladas que se pueden anidar o no. Los controladores deben seguir siendo un modelo de vista tanto como puedan, idealmente, ninguna lógica de negocios debería terminar ahí.

Entonces:

Cuando comience a conectarlos entre sí accediendo a las funciones de alcance principal, creo que corre el riesgo de acoplarlos demasiado y hacer que toda la aplicación sea ilegible y los componentes no sean reutilizables. Cuando desacopla esos datos o comportamientos compartidos en un servicio, tiene la ventaja de reutilizar todas las directivas con diferentes datos / comportamientos, incluso determinando el servicio que se utilizará en tiempo de ejecución. De eso se trata la inyección de dependencia.

RobbyD
fuente