[解決済み] Angular.jsで他者に注入できる「モノ」は何ですか?
質問
Angularの依存性注入を理解するのに少し苦労しています。私の質問は、コントローラ、ファクトリー、プロバイダなどのような"type"のどれが、同じ"type"の他のインスタンスを含む他のものに注入できるか、誰かが説明できますか?
私が実際に探しているのは、y/nで満たされたこのテーブルです。同じ行/列を持つセルについては、ある "type" の値を、同じ "type" を持つ別のものに注入することを意味します。
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Can we inject? | Constant | Controller | Directive | Factory | Filter | Provider | Service | Value |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Constant | | | | | | | | |
| Controller | | | | | | | | |
| Directive | | | | | | | | |
| Factory | | | | | | | | |
| Filter | | | | | | | | |
| Provider | | | | | | | | |
| Service | | | | | | | | |
| Value | | | | | | | | |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
どのように解決するのですか?
何の説明もなく、ただ"yes" と "no" で表を埋めていくのではなく、もう少し詳しく説明します。
[結局、予想以上に長くなってしまいました。一番下に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
パラメータと
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の各アプリケーションには、1つの
$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
と
value
は常に静的な値を返し、インジェクタを経由して呼び出されることはないため、何かで注入することはできません。
プロバイダを設定する
なぜ、本格的なプロバイダをわざわざ
provide
メソッドで本格的なプロバイダを設定する必要があるのでしょうか。
factory
,
value
などは、とても簡単です。その答えは、プロバイダが多くの設定を可能にするからです。プロバイダ(またはAngularが提供するショートカット)を使ってサービスを作成するとき、そのサービスがどのように構築されるかを定義する新しいプロバイダを作成することは既に述べました。私は
はそうしませんでした。
に注入することができるということです。
config
セクションに注入することができ、それらと対話することができます。
まず、Angularはアプリケーションを2つのフェーズで実行します。
config
と
run
のフェーズがあります。また
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!
});
ひとつだけ重要な例外があります。
constant
の中に注入することができます。
config
ブロックの中に注入することができます (これが
value
s). これらはその名前だけでアクセスされます(
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
)
コントローラの関数は注入することができますが、コントローラ自体は他のものに注入することができません。それは、コントローラはプロバイダを介して作成されないからです。その代わりに、Angularの組み込みのサービスである
$controller
と呼ばれる組み込みのサービスがあり、これがコントローラの設定を担当します。を呼び出すと
myMod.controller(...)
を呼び出すと、実際には
このサービスのプロバイダ
にアクセスしていることになります。
例えば、このようなコントローラを定義すると
myMod.controller('MainController', function($scope) {
// ...
});
実際にやっていることはこうです。
myMod.config(function($controllerProvider) {
$controllerProvider.register('MainController', function($scope) {
// ...
});
});
その後、Angular がコントローラのインスタンスを作成する必要があるとき、Angular は
$controller
サービスを使用します (そしてそのサービスは
$injector
を使用してコントローラ関数を呼び出すので、 依存関係も注入されることになります)。
フィルタとディレクティブ
filter
そして
directive
と全く同じように動作します。
controller
;
filter
というサービスを使用しています。
$filter
というサービスと、そのプロバイダである
$filterProvider
が、一方
directive
というサービスを使用しています。
$compile
というサービスと、そのプロバイダである
$compileProvider
. いくつかのリンクです。
- $filter: https://docs.angularjs.org/api/ng/service/$filter
- $filterProvider: https://docs.angularjs.org/api/ng/provider/$filterProvider
- $compile: https://docs.angularjs.org/api/ng/service/$compile
- $compileProvider: https://docs.angularjs.org/api/ng/provider/$compileProvider
他の例と同じように
myMod.filter
と
myMod.directive
は、これらのサービスを設定するためのショートカットです。
つまり、要約すると、すべての関数は
$injector.invoke
に注入することができます。
. これには、あなたのチャートから(ただし、これに限定されるものではありません。)
- コントローラー
- ディレクティブ
- ファクトリー
- フィルター
-
プロバイダ
$get
(プロバイダをオブジェクトとして定義する場合) - プロバイダ関数 (プロバイダをコンストラクタ関数として定義する場合)
- サービス
プロバイダは新しいサービスを作成します に注入することができます。 . これには
- 定数
- ファクトリー
- プロバイダ
- サービス
- 値
とはいえ、組み込みのサービスである
$controller
と
$filter
は
を注入することができます。
を使う
メソッドで定義した新しいフィルタやコントローラを取得することができます (定義したものは、それ自体ではオブジェクトに注入することができませんが)。
それ以外には、インジェクタから呼び出された関数は、プロバイダが提供するあらゆるサービスにインジェクトすることができます。
config
と
run
の違いはここに記載されています)。
関連
-
[解決済み】ASP.NET Core Dependency Injectionのエラーです。アクティブ化しようとしているときに、タイプのサービスを解決できません。
-
[解決済み】アンギュラーコンポーネントにサービスを注入しようとするとエラー "EXCEPTION: Can't resolve all parameters for component"、なぜ?
-
[解決済み] select 要素のデフォルト値を設定するための ng-option の使用方法
-
[解決済み] AngularJs ReferenceError: $http is not defined
-
[解決済み] AngularJSのグローバル変数
-
[解決済み] AngularJSでkeypressイベントを使用するには?
-
[解決済み] Apigee API へのリクエストで 401 レスポンスエラーが発生する
-
[解決済み] createspyとcreatespyobjの違いは何ですか?
-
[解決済み] なぜ依存性注入を使用するのですか?
-
[解決済み】AngularJS 。ファクトリーの代わりにサービスを使用する場合
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 方法 $state.go()
-
[解決済み] X-Frame-Options'を'SAMEORIGIN'に設定しているため、フレーム内での表示を拒否された。
-
[解決済み] Angular UI-Routerのマルチビュー
-
[解決済み] Angularのui-routerでデフォルトの状態を設定する方法
-
angularでのng-repeatとtrack by
-
[解決済み] どのように$state.goにパラメータを追加しますか?
-
[解決済み] angularJSの::の意味するところ
-
[解決済み] なぜAngularJSはselectに空のオプションを含めるのですか?
-
[解決済み] ng-repeat内のng-click関数にパラメータを追加しても、うまくいかないようです。
-
[解決済み】AngularJSのコントローラは、同じモジュール内の別のコントローラを継承できますか?