53

このアプリには 2 つのモジュールがあります。

angular.module('components', []).directive('foo', function () { return {};});
angular.module('gaad', ['components']);

このモジュールに関連するディレクティブはたくさんありますが、ここには含めません。アプリケーションは正常に動作します。ただし、モジュールのインジェクターを取得しようとするとgaad:

var injector = angular.injector(['gaad', 'components']); //called after 'gaad' module initialization

エラーがスローされます:

Uncaught Error: Unknown provider: $compileProvider from components 

現在、アプリケーションは非常に大きく、どこでバグを探すべきかわかりません。私の質問は次のとおりです。私の問題の原因は何ですか?

編集: 私は私の問題を再現することができました: http://jsfiddle.net/selbh/ehmnt/11/

4

3 に答える 3

122

質問に答える前に、モジュールごとではなく、アプリケーションごとに 1 つのインジェクター インスタンスしかないことに注意する必要があります。この意味で、モジュールごとにインジェクターを取得することはできません。もちろん、最上位のモジュールを取り上げると、それはアプリケーション全体を表します。この意味で、アプリケーションと最上位モジュールは同等に見えます。微妙な違いのように思えるかもしれませんが、この質問に完全かつ適切に答えるには、理解することが重要です。

次に、私が理解していることから、新しいインスタンスを作成するのではなく、 を取得したいと考えています。$injector問題は、引数として指定されたモジュール (アプリ)angular.injectorの新しいインスタンスを作成することです。$injectorここでは、メインの AngularJS モジュール (ng) を明示的に指定する必要があります。したがって、このコード例では:

var injector = angular.injector(['gaad', 'components']);

「gaad」および「components」モジュールで定義されたコンポーネントから新しいインジェクターを作成しようとしていて、明らかに$compileProviderカスタムモジュールで定義されていません。モジュールをリストに追加するngと、新しいインジェクターを作成することで問題が「解決」されます。これは、おそらく発生したくないことです。

実行中のアプリケーションに関連付けられたインジェクター インスタンスを実際に取得するには、次の2 つの方法を使用できます。

これは、インジェクター検索の 2 つの方法を示す jsFiddle です: http://jsfiddle.net/xaQzb/

$injector直接使用することは、単体テスト以外ではあまり一般的ではないことにも注意してください。AngularJS の世界の外から AngularJS サービスを取得するのに役立つ考えかもしれません。詳細はこちら: Call Angular JS from legacy code .

于 2012-11-15T18:16:36.500 に答える
13

インジェクターにも ng を含める必要があるようです。

var injector = angular.injector(['ng', 'b', 'a']);

From: AngularJS: インジェクター

ng モジュールは明示的に追加する必要があります。

于 2012-11-15T16:33:08.423 に答える
2

問題は、Angular のコードの実行の流れにあります。@pkozlowski.opensource の回答と関連するコメントを統合するに$injectorは、モジュール コードが実行された後にプロパティが DOM 要素で使用できるようになるため、プロパティにアクセスしたとき (アクセスしようとしたときと同じconsole.log)、プロパティは のままであることに注意してundefinedください。

この問題は、ロギング機能の実行に 0 タイムアウトを設定するだけで解決できます (つまり、ミリ秒単位の明示的な遅延は必要ありません)。このハックが機能するのは、スタックが空のとき、つまり、Angular のブートストラップが完了し、$injectorプロパティが DOM 要素で使用できるようになったときにログ機能が実行されるためです。

Angular の専門用語の別の (おそらくより良い) 解決策は、実行ブロック$injectorにアクセスするコードを含めることです (関連する APIも参照してください)。その後、通常のサービスとして初期化関数に簡単に挿入できます。これが機能するのは、すべてのブートストラップが終了したときに実行ブロックがキューに入れられ、非同期に実行されるためです。$injector

以下に、ソリューションごとに 1 つずつ、2 つのフィドルがあります。

0 タイムアウト jsFiddle

実行ブロック jsFiddle

編集

ngまた、通常、モジュールを明示的にロードする必要はありません。通常ng、Angular のコードを手動でブートストラップする必要がない限り、モデルは既に自動的に読み込まれています。回答の 1 つで参照されているドキュメントの一部は、インジェクターを手動で作成し、ロードするモジュールを指示する必要がある場合に、Angular の手動ブートストラップ手順を (暗黙のうちに、残念ながら) 参照しています。

于 2013-09-12T11:41:55.880 に答える