1. ホーム
  2. angularjs

[解決済み] Angular.jsで他者に注入できる「モノ」は何ですか?

2022-05-30 17:06:29

質問

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 定義関数)

から constantvalue は常に静的な値を返し、インジェクタを経由して呼び出されることはないため、何かで注入することはできません。

プロバイダを設定する

なぜ、本格的なプロバイダをわざわざ provide メソッドで本格的なプロバイダを設定する必要があるのでしょうか。 factory , value などは、とても簡単です。その答えは、プロバイダが多くの設定を可能にするからです。プロバイダ(またはAngularが提供するショートカット)を使ってサービスを作成するとき、そのサービスがどのように構築されるかを定義する新しいプロバイダを作成することは既に述べました。私は はそうしませんでした。 に注入することができるということです。 config セクションに注入することができ、それらと対話することができます。

まず、Angularはアプリケーションを2つのフェーズで実行します。 configrun のフェーズがあります。また config フェーズでは、 必要に応じてプロバイダを設定することができます。また、ディレクティブやコントローラ、フィルタなどの設定もここで行います。この run フェーズでは、推測できるかもしれませんが、Angularが実際にDOMをコンパイルし、アプリを起動します。

これらのフェーズで実行される追加のコードを myMod.configmyMod.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 . いくつかのリンクです。

他の例と同じように myMod.filtermyMod.directive は、これらのサービスを設定するためのショートカットです。


つまり、要約すると、すべての関数は $injector.invoke に注入することができます。 . これには、あなたのチャートから(ただし、これに限定されるものではありません。)

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

プロバイダは新しいサービスを作成します に注入することができます。 . これには

  • 定数
  • ファクトリー
  • プロバイダ
  • サービス

とはいえ、組み込みのサービスである $controller$filter を注入することができます。 を使う メソッドで定義した新しいフィルタやコントローラを取得することができます (定義したものは、それ自体ではオブジェクトに注入することができませんが)。

それ以外には、インジェクタから呼び出された関数は、プロバイダが提供するあらゆるサービスにインジェクトすることができます。 configrun の違いはここに記載されています)。