我在Angular中构建了一个基本的应用程序,但是我遇到了一个奇怪的问题,我不能将服务注入到我的一个组件中 . 它注入了我创建的其他三个组件中的任何一个 .
对于初学者来说,这是服务:
import { Injectable } from '@angular/core';
@Injectable()
export class MobileService {
screenWidth: number;
screenHeight: number;
constructor() {
this.screenWidth = window.outerWidth;
this.screenHeight = window.outerHeight;
window.addEventListener("resize", this.onWindowResize.bind(this) )
}
onWindowResize(ev: Event) {
var win = (ev.currentTarget as Window);
this.screenWidth = win.outerWidth;
this.screenHeight = win.outerHeight;
}
}
它拒绝使用的组件:
import { Component, } from '@angular/core';
import { NgClass } from '@angular/common';
import { ROUTER_DIRECTIVES } from '@angular/router';
import {MobileService} from '../';
@Component({
moduleId: module.id,
selector: 'pm-header',
templateUrl: 'header.component.html',
styleUrls: ['header.component.css'],
directives: [ROUTER_DIRECTIVES, NgClass],
})
export class HeaderComponent {
mobileNav: boolean = false;
constructor(public ms: MobileService) {
console.log(ms);
}
}
我在浏览器控制台中遇到的错误是:
EXCEPTION:无法解析HeaderComponent的所有参数:(?) .
我在bootstrap函数中有服务,所以它有一个提供程序 . 我似乎能够毫无问题地将它注入我的任何其他组件的构造函数中 .
30 回答
在我的例子中,我依赖于没有依赖关系的服务,因此我没有向服务类添加
constructor()
函数 . 我向依赖服务类添加了一个无参数构造函数,一切都开始工作了 .除了缺少
@Injectable()
装饰器在抽象类中缺少
@Injectable()
装饰器生成了无法解析服务的所有参数:(?)装饰器需要出现在MyService
以及派生类BaseService
中就我而言,我从同一个组件文件中导出了一个Class和一个Enum:
mComponent.component.ts
:然后,我试图使用
MyComponentClass
的孩子的MyEnum
. 这导致无法解决所有参数错误 .通过在
MyComponentClass
的单独文件夹中移动MyEnum
,这解决了我的问题!正如GünterZöchbauer所提到的,这种情况正在发生,因为服务或组件是循环依赖的 .
尽管可能已经提到了来自桶内的导出类的排序,但是以下场景也可以产生相同的效果 .
假设您从
A
依赖于B
和C
的同一文件中导出了类A
,B
和C
:由于Angular尚不知道依赖类(即在这种情况下为类
B
和C
)(可能在Angular在类A
上的依赖注入过程中的运行时),因此会引发错误 .解决方案
解决方案是在完成DI的类之前声明并导出依赖类 .
即,在上述情况下,类
A
在其依赖项定义后立即声明:为了搜索者的利益;我收到了这个错误 . 这只是一个缺失的@符号 .
即这会产生
Can't resolve all parameters for MyHttpService
错误 .添加缺少的
@
符号可以修复它 .就我而言,我需要将
import "core-js/es7/reflect";
添加到我的应用程序中以使@Injectable
工作 .如前所述,问题是由桶内的出口排序引起的,这是由循环依赖引起的 .
更详细的解释如下:https://stackoverflow.com/a/37907696/893630
在我的情况下,它发生是因为我没有声明构造函数参数的类型 .
我有这样的事情:
然后将其更改为下面的代码解决了我的问题 .
对我来说,当我在polyfills.ts文件中导入这个导入时出现此错误,您需要确保导入它以避免该错误 .
除了先前给出的答案之外,当您的可注射服务缺少实际的
@Injectable()
装饰器时,似乎也会抛出此错误 . 因此,在调试循环依赖项事项和导入/导出的顺序之前,请检查您的服务是否实际定义了@Injectable()
.这适用于当前的Angular最新版Angular 2.1.0 .
I opened an issue on this matter .
您必须在@Component装饰器或声明组件的模块中添加提供程序数组 . 内部组件,您可以执行以下操作:
WRONG #1: 忘记装饰者:
WRONG #2: 省略"@"符号:
WRONG #3: 省略"()"符号:
WRONG #4: 小写"i":
WRONG #5: 你忘了: import from '@angular/core';
CORRECT:
我也通过将服务A注入服务B而反之亦然 .
就个人而言, I am glad that this fails fast as it should probably be avoided anyway . 如果您希望您的服务更加模块化/可重复使用,最好尽可能避免循环引用 . 这个post强调了周围的陷阱 .
因此,我有以下建议:
如果你觉得这些类经常交互(我说的是feature envy),你可能要考虑 merging the 2 services into 1 class .
如果上述方法不适合您,请考虑使用 3rd service (
EventService
),两个服务都可以注入以便交换消息 .对我来说问题更令人讨厌,我在服务中使用服务而忘记将其添加为appModule中的依赖项!希望这有助于有人节省几个小时打破应用程序,只是为了重新 Build 它
对我来说,@ Injectable中只缺少
()
. 适当的是@Injectable()有时这会在app.module.js中声明Angular的内置模块(HttpClientModule,HttpErrorResponse等)时发生 . 我也面临同样的问题但现在已经解决了 .
我做的错误是将HttpClientModule提到 Providers 而不是 Import of angular Module
在引用
interface
时也会发生这种情况 .更改
interface
forclass
修复它,使用和不使用@Inject
.从直接声明它的文件中导入它而不是桶 .
我不知道究竟是什么导致了这个问题,但我看到它提到过几次(可能是某种循环依赖) .
它也应该通过更改桶中的出口顺序来修复(不知道细节,但也被提到)
如果您的服务 A 依赖于 static property / method 服务 B 而服务 B 本身依赖于服务 A 通过依赖注入,则会出现此错误 . 所以它's a kind of a circular dependency, although it isn' t因为属性/方法是静态的 . 可能是与 AOT 结合发生的错误 .
如果您的服务在与组件相同的文件中定义(使用它),并且该服务是在文件中的组件之后定义的,则可能会出现此错误 . 这是由于其他人提到的同一个问题 . 此时VSCode不能很好地向您显示此错误并且构建成功编译 .
由于编译器的工作方式(可能与树抖动有关),使用
--aot
运行构建可能会掩盖此问题 .Solution: 确保服务在另一个文件中或在组件定义之前定义 . (我不确定在这种情况下是否可以使用forwardRef,但这样做似乎很笨拙) .
如果我有一个非常简单的服务,它与一个组件(有点像视图模型)紧密相关 - 例如 .
ImageCarouselComponent
,我可以将其命名为ImageCarouselComponent.service.ts
,因此它不会与我的其他服务混淆 .在我的情况下,这是因为插件Augury,禁用它将工作正常 . 替代选项是aot,也有效 .
归功于@ Boboss74,他在这里发布了答案:https://github.com/angular/angular/issues/23958
对我来说,这是因为我的
@Component
装饰器和我的Component类之间有一条空行 . 这导致装饰器无法应用于类 .我通过错误输入服务的名称,即构造函数(private myService:MyService)来遇到此错误 .
对于拼写错误的服务,我可以通过检查Chrome-> Console中的页面来确定哪个服务是问题(我在构造函数中列出了几个) . 您将通过显示对象Object,object Object,?作为消息的一部分看到“参数”数组列表 . (或类似的东西) . 注意“?”的位置是,这是导致问题的服务的位置 .
另一种可能性是在tsconfig.json中没有将
emitDecoratorMetadata
设置为true在我的情况下,我试图扩展“
NativeDateAdapter
" in order to override "format(date: Date, displayFormat: Object)
”方法 .在AngularMaterial-2 DatePicker中 .
所以基本上我忘了添加
@Injectable
anotation .将此添加到我的“CustomDateAdapter”类后:
错误消失了 .
从Angular
2.2.3
开始,现在有一个forwardRef()
实用程序函数,允许您注入尚未定义的提供程序 .未定义,我的意思是依赖注入映射不知道标识符 . 这是循环依赖期间发生的情况 . 您可以在Angular中使用非常难以解开和查看的循环依赖项 .
在原始问题的源代码中将
@Inject(forwardRef(() => MobileService))
添加到构造函数的参数将解决问题 .参考文献
Angular 2 Manual: ForwardRef
Forward references in Angular 2
从injectable constructor()方法中删除参数解决了我的情况 .
使用桶进口时 - 请考虑首先导入注射剂作为经验法则 .
在我的情况下,将错误的参数传递给构造函数会生成此错误,关于此错误的基本想法是您在不知不觉中将一些错误的args传递给任何函数 .
我通过删除该参数解决了这个问题 .
就我而言,它是一个循环引用 . 我让MyService调用Myservice2和MyService2调用MyService .
不好 :(