53

我有这个应用程序有两个模块:

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

在回答这个问题之前,我们需要注意每个应用程序只有一个注入器实例,而不是每个模块。从这个意义上说,不可能为每个模块检索一个注入器。当然,如果我们采用顶层模块,它代表了整个应用程序。从这个意义上说,应用程序和顶级模块似乎是等价的。这似乎是一个微妙的差异,但为了完全正确地回答这个问题,理解这一点很重要。

接下来,据我所知,您想检索$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']);

来自:AngularJS:注入器

ng 模块必须显式添加。

于 2012-11-15T16:33:08.423 回答
2

问题在于 Angular 代码的执行流程。要集成@pkozlowski.opensource 的答案和相关评论,请注意该$injector属性在模块代码执行后可用于 DOM 元素,因此当您访问该属性时(当您尝试访问该属性时console.log)该属性仍然是undefined.

您可以通过简单地将日志功能的执行设置为 0 超时来解决这个问题(即,不需要以毫秒为单位的显式延迟)。$injector这个 hack 之所以有效,是因为当堆栈为空时,即 Angular 的引导完成并且该属性可用于 DOM 元素时,将执行日志记录功能。

Angular 术语中的另一个(也许更好)解决方案是将您的$injector-accessing 代码包含在运行块中(另请参见相关 API)。然后$injector可以很容易地将其作为普通服务注入到初始化函数中。这是可行的,因为当所有引导终止时,运行块会排队并异步执行。

您可以在下面找到两个小提琴,每个解决方案一个。

0 超时 jsFiddle

运行块 jsFiddle

编辑

此外,通常不需要显式加载ng模块。在正常情况下,ng模型已经自动加载,除非你想手动引导 Angular 的代码。答案之一中引用的文档(隐含地,不幸的是)指的是Angular的手动引导过程,当您必须手动创建注入器并告诉它您要加载哪些模块时

于 2013-09-12T11:41:55.880 回答