Angular の依存性注入を理解するのに少し苦労しています。質問ですが、コントローラー、ファクトリー、プロバイダーなどのどの「タイプ」を、同じ「タイプ」の他のインスタンスを含め、他のものに注入できるか説明してもらえますか?
私が実際に探しているのは、y/n で埋められたこの表です。同じ行/列のセルの場合、それは 1 つの「タイプ」の値を同じ「タイプ」の別のセルに注入することを意味します。
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Can we inject? | Constant | Controller | Directive | Factory | Filter | Provider | Service | Value |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Constant | | | | | | | | |
| Controller | | | | | | | | |
| Directive | | | | | | | | |
| Factory | | | | | | | | |
| Filter | | | | | | | | |
| Provider | | | | | | | | |
| Service | | | | | | | | |
| Value | | | | | | | | |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
ベストアンサー1
説明なしに「はい」と「いいえ」を表に記入するだけではなく、もう少し詳しく説明します。
[注記、書き終えた後に追加: 結局、これは予想していたよりもかなり長くなりました。最後に 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 はプロバイダーの関数を呼び出して、サービスの新しいインスタンスを返します。 この場合、注入されるのは、名前に基づいてパラメーターとsa メッセージ$get
を受け取る関数です。 次のように使用できます。name
alert
app.controller('MainController', function($scope, greeting) {
$scope.onClick = function() {
greeting('Ford Prefect');
};
});
さて、ここに秘訣があります。 factory
、、service
は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);
インジェクターはサービスのインスタンスのみを作成することに注意してください一度次に、プロバイダーがサービス名で返すものをキャッシュします。次にサービスを要求したときに、実際にまったく同じオブジェクトが取得されます。
それで、あなたの質問に答えると、サービスを注入することができます呼び出される関数は$injector.invoke
。 これも
- コントローラ定義関数
- ディレクティブ定義関数
- フィルタ定義関数
$get
プロバイダーのメソッド(定義関数とも呼ばれるfactory
)
constant
s とs は常に静的な値を返すためvalue
、インジェクター経由で呼び出されることはなく、したがって、それらに何かを注入することはできません。
プロバイダーの設定
provide
、などがこんなに簡単なのにfactory
、なぜわざわざメソッドを使って本格的なプロバイダを設定する必要があるのかと不思議に思うかもしれませんvalue
。その答えは、プロバイダは多くの設定を可能にするからです。プロバイダ(またはAngularが提供するショートカットのいずれか)を介してサービスを作成すると、そのサービスの構築方法を定義する新しいプロバイダが作成されることはすでに述べました。しなかったここで言及しておきたいのは、これらのプロバイダーをアプリケーションのセクションに挿入してconfig
、それらを操作できるということです。
まず、Angular はアプリケーションを フェーズconfig
とrun
フェーズの 2 つのフェーズで実行します。config
フェーズでは、これまで見てきたように、必要に応じてプロバイダーを設定できます。また、ディレクティブ、コントローラー、フィルターなどもここで設定されます。 フェーズではrun
、ご想像のとおり、Angular が実際に DOM をコンパイルしてアプリを起動します。
これらのフェーズで実行する追加コードを関数myMod.config
と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 つあります。constant
は変更できないため、ブロック内に挿入できますconfig
(これが との違いですvalue
)。 は名前だけでアクセスされます (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
使用して をカスタマイズできます。alert
ブロック内でこのプロバイダーにアクセスし、config
このメソッドを呼び出してサービスをカスタマイズできます。最終的にアプリを実行すると、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
コントローラー関数を呼び出すため、その依存関係も注入されます)。
フィルターとディレクティブ
filter
および はdirective
とまったく同じように動作しますcontroller
。filter
は というサービス$filter
とそのプロバイダを使用し$filterProvider
、 はdirective
というサービス$compile
とそのプロバイダを使用します$compileProvider
。いくつかのリンク:
- $フィルター:https://docs.angularjs.org/api/ng/service/$filter
- $フィルタープロバイダー:https://docs.angularjs.org/api/ng/provider/$filterProvider
- $コンパイル:https://docs.angularjs.org/api/ng/service/$compile
- $コンパイルプロバイダー:https://docs.angularjs.org/api/ng/provider/$compileProvider
他の例と同様に、myMod.filter
および はmyMod.directive
これらのサービスを構成するためのショートカットです。
まとめると、$injector.invoke
注入できるこれには、チャートから次のものが含まれます (ただし、これらに限定されません)。
- コントローラ
- 指令
- 工場
- フィルター
- プロバイダー
$get
(プロバイダーをオブジェクトとして定義する場合) - プロバイダー関数(プロバイダーをコンストラクター関数として定義する場合)
- サービス
プロバイダーは新しいサービスを作成する物に注入できる。 これも:
- 絶え間ない
- 工場
- プロバイダー
- サービス
- 価値
とはいえ、組み込みのサービス$controller
や$filter
できる注射すれば、使用これらのサービスを使用して、これらのメソッドで定義した新しいフィルターとコントローラーを取得します (定義したもの自体を他のものに挿入することはできませんが)。
それ以外では、インジェクターによって呼び出される関数は、プロバイダーが提供するサービスを使用して注入できます。制限はありません (ここに記載されているconfig
および のrun
違いを除く)。