web-dev-qa-db-ja.com

angularjsディレクティブはサービスと直接対話する必要がありますか、それともアンチパターンと見なされますか?

どちらが優れていると考えられますか:

  • サービスと直接対話するディレクティブがある

または

  • コントローラが動作をバインドする可能性がある特定のフックを公開するディレクティブ(サービスを含む)がありますか?
36
WTK

ディレクティブは、(経験則として)短く(コード的に)、(潜在的に)再利用可能で、機能の範囲が限定されている場合に最適です。 UIを含み、サービス(バックエンドへの接続を処理すると想定している)に依存するディレクティブを作成すると、次の2つの機能的な役割が与えられます。

  • ウィジェットのデータの表示/入力のためのUIの制御。
  • (サービスを介して)バックエンドに送信します。

ただし、別のサービスや別のUIで(少なくとも簡単には)再び使用することはできないため、再利用性が低下します。

これらの決定を行うとき、組み込みのHTML要素と比較することがよくあります。たとえば、<input><textarea><form>など:特定のバックエンドから完全に独立しています。 HTML5は<input>要素にいくつかの追加の型を与えています。 date、これはまだバックエンドから独立しており、データの正確な場所または使用方法を示します。それらは純粋にインターフェース要素です。ディレクティブを使用して作成されたカスタムウィジェットは、可能であれば同じパターンに従う必要があると思います。

しかし、これで話は終わりではありません。組み込みのHTML要素との類似性を超えて、サービスを呼び出す再利用可能なディレクティブを作成し、<textarea>を使用する場合と同様に、純粋にUIディレクティブを使用できます。次のようにHTMLを使用したいとします。

<document document-url="'documents/3345.html'">
 <document-data></document-data>
 <comments></comments>
 <comment-entry></comment-entry>
</document>

commentEntryディレクティブをコード化するには、サービスをUIウィジェットとリンクするコントローラーのみを含む非常に小さなディレクティブを作成できます。何かのようなもの:

app.directive('commentEntry', function (myService) {
  return {
    restrict: 'E',
    template: '<comment-widget on-save="save(data)" on-cancel="cancel()"></comment-widget>',
    require: '^document',
    link: function (scope, iElement, iAttrs, documentController) {
      // Allow the controller here to access the document controller
      scope.documentController = documentController;
    },
    controller: function ($scope) {
      $scope.save = function (data) {
        // Assuming the document controller exposes a function "getUrl"
        var url = $scope.documentController.getUrl(); 

        myService.saveComments(url, data).then(function (result) {
          // Do something
        });
      };
    }
  };
});

これを極端にすると、HTMLに手動でng-controller属性を設定する必要がなくなる可能性があります。それぞれに明確な「UI」の役割または明確な「役割」がある限り、ディレクティブを使用してすべてそれを行うことができます。データ」の役割。

私が言及しなければならない欠点があります。それは、アプリケーションに「可動部分」を追加するため、少し複雑になります。ただし、各部分に明確な役割があり、十分に機能している場合(単体+ E2Eテスト済み)、それは価値があり、長期的には全体的なメリットがあります。

24
Michal Charemza

Michal Charemzaの回答に同意しません。

彼の答えは理論的には正しいですが、現実の世界ではあまり実用的ではありません。

私はそのように考えていて、私と私のチームが構築している大きな現実の世界のアプリにそれを強制しようとしたので、それが面倒になりすぎたと言っています。

HTML言語との類似性は良くありません。なぜなら、Webブラウザーのような一般的なアプリケーションを構築するのではないため、汎用の非常に再利用可能なディレクティブを構築しようと努力すべきではないからです。

代わりに、ディレクティブを使用して、独自のドメインに存在するアプリのドメイン固有言語(DSL)を構築する必要があります。

これは、すべてのディレクティブが一般的なものであってはならないという意味ではありません。それが彼らの性質にあるならば、いくつかはそうかもしれません。カスタムの日付ピッカーを作成している場合は、必ず汎用的なものにし、アプリ間で再利用できるようにしてください。

しかし、バックエンドにバインドするログインボックスのようなものを構築している場合は、それを実行してください。

唯一の経験則は次のとおりです。コードを複製しないでください(ファクトリやサービスに小さな断片を抽出しないでください)。依存関係の注入によってテスト可能にします。幸いなことに、Angularを使用すれば、それらは簡単なものです。

複雑にしないでおく。 :)

60
Dema

「ディレクティブがサービスと相互作用するべきか」という質問は、サービスが何をしているかに依存すると思います。

私はディレクティブがHTTPリクエストで何もしないサービスとやり取りしてきましたが、それは良いパターンだと思います。サービス/ファクトリーは、よりデータ指向のロジックをカプセル化するのに最適であり、ディレクティブは、プレゼンテーション指向のロジックをカプセル化するのに最適です。 Angular docsに記載されているサービスの目的は次のとおりです:「サービスを使用して、アプリ全体でコードを整理および共有することができます。」それはかなり広いですが、サービスはディレクティブでその目標を達成するために使用できます。

そうは言っても、ディレクティブが直接HTTPリクエストを行わないようにしたい場合があることは理解しています。繰り返しますが、それはサービスと、サービスの編成方法によって異なります。

2
ccnokes

AngularJSフレームワークに従って、サーバーからデータを取得するには、ファクトリー/サービスをシングルトン化する必要があります。これらのファクトリを同じものを書き直さずにアプリケーション全体で再利用できるようにするために、ディレクティブ内でこれらのファクトリを呼び出して、Api /サーバーからデータをフェッチできます。

1