Angular.jsで他の人に注入できる「もの」は何ですか?


142

AngularのDependency Injectionを理解するのに少し苦労しています。だから私の質問は、コントローラ、ファクトリ、プロバイダなどの「タイプ」のどれを、同じ「タイプ」の他のインスタンスを含めて他の人に注入できるのか誰でも説明できますか?

私が実際に探しているのは、このテーブルにy / nが入ったものです。同じ行/列のセルの場合、これはある「タイプ」の値を同じ「タイプ」の別の「タイプ」に注入することを意味します

+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Can we inject? | Constant | Controller | Directive | Factory | Filter | Provider | Service | Value |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Constant       |          |            |           |         |        |          |         |       |
| Controller     |          |            |           |         |        |          |         |       |
| Directive      |          |            |           |         |        |          |         |       |
| Factory        |          |            |           |         |        |          |         |       |
| Filter         |          |            |           |         |        |          |         |       |
| Provider       |          |            |           |         |        |          |         |       |
| Service        |          |            |           |         |        |          |         |       |
| Value          |          |            |           |         |        |          |         |       |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+

回答:


391

表に「はい」と「いいえ」を説明なしで記入するのではなく、もう少し詳しく説明します。

[注、終了後に追加されました。これは最終的に...予想よりもかなり長くなりました。一番下にtl; drがありますが、これが情報として役立つことを願っています。]

[この回答はAngularJS wikiにも追加されています:依存性注入について ]


プロバイダー($provide

この$provideサービスは、Angularに新しい注射可能なものを作成する方法を伝える責任があります。これらはサービスと呼ばれます。サービスは、プロバイダーと呼ばれるものによって定義されます。プロバイダーとは、使用時に作成するものです$provide。プロバイダーの定義provider$provideサービスのメソッドを介して行わ$provideれ、アプリケーションのconfig関数に挿入するように要求することでサービスを取得できます。例は次のようなものです:

app.config(function($provide) {
  $provide.provider('greeting', function() {
    this.$get = function() {
      return function(name) {
        alert("Hello, " + name);
      };
    };
  });
});

ここでは、というサービスの新しいプロバイダーを定義しましたgreeting。名前を付けた変数を注入greeting可能な関数(コントローラーなど、後で詳しく説明します)に注入できます。Angular $getは、サービスの新しいインスタンスを返すためにプロバイダーの関数を呼び出します。この場合、注入されるのは、名前に基づいてnameパラメーターとalertsaメッセージを受け取る関数です。次のように使用します。

app.controller('MainController', function($scope, greeting) {
  $scope.onClick = function() {
    greeting('Ford Prefect');
  };
});

今ここにトリックがあります。 factoryservice、およびvalueプロバイダの種々の部分を定義するためにすべてのちょうどショートカットである-は、彼らはすべてのものを入力することなく、プロバイダを定義する手段を提供します。たとえば、次のようにまったく同じプロバイダーを作成できます。

app.config(function($provide) {
  $provide.factory('greeting', function() {
    return function(name) {
      alert("Hello, " + name);
    };
  });
});

理解することが重要なので、言い換えます。内部的には、AngularJSは上記で記述したのとまったく同じコード$provide.providerバージョン)呼び出しています。文字通り、2つのバージョンに100%の違いはありません。valueまったく同じように動作します。$get関数(別名、factory関数)から返すものが常にまったく同じである場合、を使用してさらに少ないコードを記述できますvalue。たとえば、greetingサービスには常に同じ関数を返すため、これを使用valueして定義することもできます。

app.config(function($provide) {
  $provide.value('greeting', function(name) {
    alert("Hello, " + name);
  });
});

繰り返しますが、これは、この関数を定義するために使用した他の2つのメソッドと100%同一です。これは、いくつかの入力を節約する方法にすぎません。

さて、おそらくapp.config(function($provide) { ... })私が使用してきたこの迷惑なことに気づいたでしょう。(上記の任意のメソッドを介して)新しいプロバイダーを定義することは非常に一般的であるため、AngularJSは$providerメソッドをモジュールオブジェクトに直接公開して、さらに入力を節約します。

var myMod = angular.module('myModule', []);

myMod.provider("greeting", ...);
myMod.factory("greeting", ...);
myMod.value("greeting", ...);

これらはすべて、app.config(...)以前に使用したより詳細なバージョンと同じことを行います。

これまでにスキップした注射剤はconstantです。今のところ、と同じように機能すると簡単に言うことができvalueます。後で1つの違いがあることがわかります。

を確認すると、これらのコードはすべてまったく同じことを行っています。

myMod.provider('greeting', function() {
  this.$get = function() {
    return function(name) {
      alert("Hello, " + name);
    };
  };
});

myMod.factory('greeting', function() {
  return function(name) {
    alert("Hello, " + name);
  };
});

myMod.value('greeting', function(name) {
  alert("Hello, " + name);
});

インジェクター($injector

インジェクターは、提供されたコードを使用してサービスのインスタンスを実際に作成します$provide(しゃれは意図されていません)。注入された引数を取る関数を書くときはいつでも、インジェクターが機能しているのが見えます。各AngularJSアプリケーションには$injector、アプリケーションの初回起動時に作成されるシングルがあります。あなたは$injectorどんな注射可能な関数に注射することによってそれを手に入れることができます(はい、$injectorそれ自身を注射する方法を知っています!)

あなたがしたら$injector、あなたは呼び出すことで定義されたサービスのインスタンスを取得することができget、サービスの名前で、その上に。例えば、

var greeting = $injector.get('greeting');
greeting('Ford Prefect');

インジェクターは、サービスを関数にインジェクトする責任もあります。たとえば、インジェクターのinvokeメソッドを使用して、任意の関数に魔法のようにサービスを注入できます。

var myFunction = function(greeting) {
  greeting('Ford Prefect');
};
$injector.invoke(myFunction);

インジェクタはサービスのインスタンスを1回だけ作成することに注意してください。次に、プロバイダーがサービスの名前で返すものをすべてキャッシュします。次にサービスを要求すると、実際にはまったく同じオブジェクトが取得されます。

したがって、質問に答えるために、で呼び出されるすべての関数に$injector.invokeサービスを注入できます。これも

  • コントローラー定義関数
  • ディレクティブ定義関数
  • フィルター定義関数
  • $getプロバイダーのメソッド(別名factory定義関数)

以来constantsおよびvalue常に静的な値を返すよ、彼らはインジェクタ経由で起動されていないので、あなたは何でそれらを注入することはできません。

プロバイダーの構成

、などがはるかに簡単なprovide場合factoryvalue、誰もがメソッドを使用して本格的なプロバイダーを設定するのに煩わしいのか疑問に思うかもしれません。その答えは、プロバイダーが多くの設定を許可することです。プロバイダー(またはAngularが提供する任意のショートカット)を介してサービスを作成すると、そのサービスの構築方法を定義する新しいプロバイダーを作成することはすでに説明しました。私言及しなかったことは、これらのプロバイダーをconfigアプリケーションのセクションに挿入して、それらを操作できることです!

-まず、角度を二段階でアプリケーションを実行configし、run段階。これconfigまで見てきたように、フェーズでは、必要に応じてプロバイダーをセットアップできます。これは、ディレクティブ、コントローラー、フィルターなどが設定される場所でもあります。runご想像のとおり、このフェーズでは、Angularが実際にDOMをコンパイルしてアプリを起動します。

myMod.configand myMod.run関数を使用して、これらのフェーズで実行するコードを追加できます。それぞれが特定のフェーズで実行する関数を取得します。最初のセクションで説明したように、これらの関数は注入可能$provideです。最初のコードサンプルに組み込みサービスを注入しました。ただし、注目に値するのはconfigフェーズ中に注入できるのはプロバイダーのみですAUTOモジュール内のサービスを除い$provide$injector)。

たとえば、以下は許可されていません

myMod.config(function(greeting) {
  // WON'T WORK -- greeting is an *instance* of a service.
  // Only providers for services can be injected in config blocks.
});

あなたがやるへのアクセス権を持ってしても、あるプロバイダあなたが作ったサービスのために:

myMod.config(function(greetingProvider) {
  // a-ok!
});

重要な例外が1つあります。sはconstant変更できないため、configブロック内に挿入できます(これがvalues との違いです)。名前だけでアクセスされます(Providerサフィックスは不要)。

あなたは、プロバイダの命名されることを、サービスのプロバイダを定義したときはいつでもserviceProvider、どこserviceサービスの名前です。これで、プロバイダーの力を使用して、さらに複雑なことを行うことができます!

myMod.provider('greeting', function() {
  var text = 'Hello, ';

  this.setText = function(value) {
    text = value;
  };

  this.$get = function() {
    return function(name) {
      alert(text + name);
    };
  };
});

myMod.config(function(greetingProvider) {
  greetingProvider.setText("Howdy there, ");
});

myMod.run(function(greeting) {
  greeting('Ford Prefect');
});

これで、プロバイダー上にsetTextをカスタマイズするために使用できる関数が呼び出されましたalertconfigブロックでこのプロバイダーにアクセスして、このメソッドを呼び出し、サービスをカスタマイズできます。最後にアプリを実行したら、greetingサービスを取得し、試してカスタマイズが有効になったことを確認できます。

これはより複雑な例なので、実際に動作するデモを次に示します。http//jsfiddle.net/BinaryMuse/9GjYg/

コントローラ($controller

コントローラー関数を注入することはできますが、コントローラー自体を他のものに注入することはできません。これは、コントローラーがプロバイダー経由で作成されていないためです。代わりに、$controllerコントローラーのセットアップを担当するというAngularサービスが組み込まれています。を呼び出すとmyMod.controller(...)、前のセクションと同じように、実際にこのサービスのプロバイダーにアクセスしています。

たとえば、次のようなコントローラーを定義するとします。

myMod.controller('MainController', function($scope) {
  // ...
});

あなたが実際にやっていることはこれです:

myMod.config(function($controllerProvider) {
  $controllerProvider.register('MainController', function($scope) {
    // ...
  });
});

その後、Angularがコントローラーのインスタンスを作成する必要がある場合、$controllerサービスを使用します(サービスはを使用し$injectorてコントローラー関数を呼び出し、依存関係も注入されます)。

フィルターとディレクティブ

filterdirectiveまったく同じように動作しcontrollerます。filterと呼ばれるサービス$filterとそのプロバイダー$filterProviderdirective使用し、と呼ばれるサービス$compileとそのプロバイダーを使用します$compileProvider。いくつかのリンク:

他の例myMod.filterと同様に、myMod.directiveこれらのサービスを構成するためのショートカットです。


tl; dr

つまり、まとめると、で呼び出されるすべての関数を$injector.invoke に注入できます。これには、チャートからの制限が含まれます(ただし、これらに限定されません)。

  • コントローラ
  • 指令
  • 工場
  • フィルタ
  • プロバイダー$get(プロバイダーをオブジェクトとして定義する場合)
  • プロバイダー関数(プロバイダー関数をコンストラクター関数として定義する場合)
  • サービス

プロバイダーは、物事に注入できる新しいサービス作成します。これも:

  • 絶え間ない
  • 工場
  • プロバイダー
  • サービス

それはのようなサービスを内蔵し、言った$controller$filter することができます注入することが、あなたがすることができます使用しますすることができ、自分自身で、あなたが定義した事がなくても(あなたがそれらのメソッドで定義された新しいフィルターとコントローラのホールドを取得するには、これらのサービスを物に注入された)。

それ以外の、任意のインジェクタ呼び出される関数は、プロバイダーが提供するサービスを注入することができる- (以外に制限がないconfigrun違い、本明細書に記載されているが)。


6
うわー!こんなに詳しく答えてくれてありがとう!これを2度読んだことがあり、かなり理解できたと思います。それとあなたが今日後で詳細に与えたリンクとそれを研究するつもりです。そして猫のためのもう一つの+1。:)
user1527166 2013年

18
私が出会った中で最も有用で詳細なSO回答の1つ-ありがとう!
Godders 2013

11
この答えは、素晴らしいレベルを新たに定義します。照明のもの。
Ngure Nyaga 2013

4
AngularJSについて私が出会った中で最高のリソースです。ありがとう。
code90

5
文字通り、私が見たAngularJSのドキュメントの中で最も優れたものです。行くぞ!
Iain Duncan

13

BinaryMuseが提供するプロバイダー、ファクトリー、サービスについての彼女の驚くべき答えの中で述べている点は、すべて同じものであることは非常に重要です。

以下は、彼女のポイントを視覚的に説明できると思う画像です。

AngularJSはすべてプロバイダーです
(ソース:simplygoodcode.com


7

ミシェルによる素晴らしい答え。ディレクティブを挿入できることを指摘したいだけです。あなたが名前のディレクティブを持っている場合はmyThing、あなたがそれを注入することができますmyThingDirectiveここでは不自然な例です

上記の例はあまり実用的ではありませんが、ディレクティブを挿入する機能は、そのディレクティブを装飾する場合に役立ちます。


Angular 1.4以降、そのディレクティブを装飾する2番目の例は機能しないようです。(そこでのフアンビスカイアのコメントを参照)
Vadorequest '11
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.