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


35

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

  • サービスと直接やり取りするディレクティブを持つ

または

  • コントローラが動作をバインドする特定のフックを公開するディレクティブを持っていますか?

あなたが達成したいこと、伝えられること、予想されるソースコードの量、ドメインとは何か、どのようにスケーリングする必要があるのか​​、もう少しコンテキストが必要です。
ユーザー

これは、コメントウィジェットのレンダリングを行うディレクティブです。コメントフィールドと、送信/キャンセルボタンを表示します。このディレクティブは、「ドキュメント」にコメントを付けるという1つのコンテキストでのみ使用されることを想定しています。現在コントローラーを処理する方法は、実際のコメントを作成するための関数を公開することです(コントローラーはコメントサービスのインジェクションインスタンスを取得します)。それを行うもう1つの方法は、(エラー/成功処理とともに)全体をディレクティブにカプセル化することです(ディレクティブはコメントサービスを挿入します)。
WTK

回答:


24

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

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

また、別のサービスや別のUIで(少なくとも簡単に)使用できないため、再利用しにくくします。

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

ただし、これで話は終わりではありません。組み込みのHTML要素との類似性を超えて、サービスを呼び出す再利用可能なディレクティブを作成し、純粋にUIディレクティブを使用できます<textarea>。次のように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
        });
      };
    }
  };
});

これを極端にするng-controllerと、HTMLに手動の属性を持つ必要はないかもしれません。それぞれが明確な「UI」ロールまたは明確な「データ」ロールを持っている限り、ディレクティブを使用してすべて行うことができます。

私が言及しなければならない欠点があります:それは、アプリケーションにより多くの「可動部分」を与え、それは少し複雑さを追加します。ただし、各部分に明確な役割があり、うまく機能している場合(ユニット+ E2Eテスト済み)、それは価値があり、長期的には全体的な利点があると主張します。


59

Michal Charemzaの答えに反対させてください。

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

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

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

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

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

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

唯一の経験則は次のとおりです。コード(工場やサービスの一部を抽象化しない)を決して複製せず、依存性注入によってテスト可能にします。幸いなことに、Angularでは、これらは非常に簡単です。

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


5
良い点Dema-Michalの答えを受け入れましたが、あなたのアプローチには同意しますが、単に目的のために何かを再利用できるようにするためにフープを飛ばすべきではないということです。それは私の最初の本能でした。サービスをディレクティブでバインドするのは理にかなっているからです。これは、angularjsの達人がそれを行うかしないかの理由ではありません。最後に、サービスを直接注入したディレクティブを作成し、パブリックAPIとして、コメントが実際に作成された後に起動されるコールバックのフックを提供します。
WTK 14年

2

「ディレクティブがサービスと対話する必要がある」という質問は、サービスの実行内容に依存すると思います。

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

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


1

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.