web-dev-qa-db-ja.com

ネストされたディレクティブ間の通信

指令間の通信にはかなりの数の方法があるようです。ネストされたディレクティブがあるとします。内部のディレクティブは外部に何かを伝える必要があります(たとえば、ユーザーが選択したもの)。

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

これまでのところ、これを行うには5つの方法があります

require:親ディレクティブ

innerディレクティブはouterディレクティブを必要とする場合があり、そのコントローラー上のいくつかのメソッドを公開できます。したがって、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);
   }
}

そしてouterディレクティブのコントローラで:

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

$emitイベント

innerディレクティブは$emitイベントを$onを介してouterディレクティブが応答できるイベントにすることができます。したがって、innerディレクティブのコントローラで:

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

outerディレクティブコントローラで:

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

&を介して親スコープで式を実行します

アイテムは、親スコープの式にバインドして、適切なポイントで実行できます。 HTMLは次のようになります。

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

したがって、innerコントローラには、呼び出すことができる「innerChoose」関数があります

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

(この場合)outerディレクティブのスコープで 'functionOnOuter'関数を呼び出します。

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

非分離スコープでのスコープ継承

これらがネストされたコントローラーであることを考えると、スコープの継承が機能している可能性があり、分離されたスコープがない限り、内部ディレクティブはスコープチェーン内の任意の関数を呼び出すことができます)。したがって、innerディレクティブで:

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

そしてouterディレクティブで:

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

内側と外側の両方に注入されるサービスによって

両方のディレクティブにサービスを挿入できるため、同じオブジェクトに直接アクセスしたり、関数を呼び出してサービスに通知したり、通知を受けるように自分自身を登録したりすることもできます。これには、ディレクティブをネストする必要はありません。

質問:それぞれの潜在的な欠点と利点は何ですか?

61
Michal Charemza

ディレクティブの&定義をAPIと見なしているため、私の好みは、主にディレクティブスコープでscope: {}属性を定義することです。スコープ属性の定義を調べて、ディレクティブが適切に機能するために必要な情報を確認する方が、リンクされたイベントと$emitのイベント、継承されたスコープ関数または注入されたコントローラー内で使用される関数を探すよりもはるかに簡単です。

7
Jeff Swensen

私の意見:

サービスは、モジュール/ディレクティブ/コントローラー間で動作/データを共有するための推奨される方法です。ディレクティブは、ネストできるかどうかに関係なく分離されたものです。コントローラーはできる限りビューモデルであることに固執する必要があります。理想的には、ビジネスロジックがそこに到達してはなりません。

そう:

親スコープ関数にアクセスしてそれらを一緒に配線し始めると、それらを非常に強く結合し、アプリケーション全体が読み取り不能になり、コンポーネントが再利用できなくなるリスクがあると思います。サービスでその共有データまたは動作を分離すると、実行時に使用するサービスを決定する場合でも、異なるデータ/動作でディレクティブ全体を再利用できるという利点があります。これが依存性注入のすべてです。

1
RobbyD