web-dev-qa-db-fra.com

Communication entre les directives imbriquées

Il semble qu'il existe plusieurs façons de communiquer entre les directives. Supposons que vous ayez des directives imbriquées, où les directives internes doivent communiquer quelque chose à l'extérieur (par exemple, elles ont été choisies par l'utilisateur).

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

Jusqu'à présent, j'ai 5 façons de le faire

require: directive parent

La directive inner peut nécessiter la directive outer, qui peut exposer une méthode sur son contrôleur. Donc dans la définition inner

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

Et dans le contrôleur de la directive outer:

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

$emit un événement

La directive inner peut $emit un événement auquel la directive outer peut répondre, via $on. Donc, dans le contrôleur de la directive inner:

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

et dans le contrôleur de directives outer:

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

Exécuter l'expression dans la portée parent, via &

L'élément peut se lier à une expression dans la portée parent et l'exécuter à un point approprié. Le HTML serait comme:

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

Ainsi, le contrôleur inner a une fonction 'innerChoose' qu'il peut appeler

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

qui appellerait (dans ce cas) la fonction 'functionOnOuter' sur la portée de la directive outer:

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

Héritage de portée sur une portée non isolée

Étant donné qu'il s'agit de contrôleurs imbriqués, l'héritage de portée peut être à l'œuvre et la directive interne peut simplement appeler toutes les fonctions de la chaîne de portée, tant qu'elle n'a pas de portée isolée). Donc dans la directive inner:

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

Et dans la directive outer:

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

Par service injecté à la fois intérieur et extérieur

Un service peut être injecté dans les deux directives, afin qu'elles puissent avoir un accès direct au même objet, ou appeler des fonctions pour notifier le service, et peut-être même s'enregistrer pour être notifié, dans un système pub/sub. Cela ne nécessite pas l'imbrication des directives.

Question: Quels sont les inconvénients et avantages potentiels de chacun par rapport aux autres?

61
Michal Charemza

Ma préférence va à la définition d'un & attribut dans la portée de la directive principalement parce que je vois le scope: {} définition d'une directive comme API. Il est beaucoup plus facile de regarder une définition d'attribut de portée pour voir de quelles informations la directive a besoin pour fonctionner correctement que pour parcourir les fonctions de liaison et de contrôleur pour $emit 'd événements, fonctions de portée héritées ou fonctions utilisées dans les contrôleurs injectés.

7
Jeff Swensen

Mon avis:

Les services sont le moyen préféré de partager le comportement/les données entre les modules/directives/contrôleurs. Les directives sont des choses isolées qui peuvent être imbriquées ou non. Les contrôleurs devraient rester autant que possible un modèle de vue, idéalement aucune logique métier ne devrait s'y retrouver.

Donc:

Lorsque vous commencez à les connecter ensemble en accédant aux fonctions de portée parent, je pense que vous risquez de les coupler beaucoup trop fort et de rendre l'ensemble de l'application illisible et les composants non réutilisables. Lorsque vous dissociez ces données ou comportements partagés dans un service, vous avez l'avantage de réutiliser l'ensemble des directives avec des données/comportements différents, même en déterminant le service à utiliser lors de l'exécution. C'est à cela que sert l'injection de dépendance.

1
RobbyD