我已经在 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);
}
}
我在浏览器控制台中得到的错误是:
例外:无法解析 HeaderComponent 的所有参数:(?)。
我在引导函数中有服务,所以它有一个提供者。而且我似乎能够毫无问题地将它注入到我的任何其他组件的构造函数中。
'../'
是 index.ts
(桶)吗?您可以尝试从直接声明它的文件中导入它吗?
从直接声明它的文件而不是桶中导入它。
我不知道究竟是什么导致了这个问题,但我看到它多次提到(可能是某种循环依赖)。
它也应该可以通过改变桶中出口的顺序来解决(不知道细节,但也提到过)
除了之前给出的答案之外,当您的可注入服务缺少实际的 @Injectable()
装饰器时,似乎也会引发此错误。因此,在调试循环依赖项和导入/导出顺序之前,请先简单检查一下您的服务是否确实定义了 @Injectable()
。
这适用于当前最新的 Angular Angular 2.1.0。
I opened an issue on this matter。
Router
,而没有该可注入,这个错误总是会发生(只要您决定一行代码使用注入的路由器。
@injectable()
。这本身就是另一个奇怪之处。为了更好的衡量,我仍然会添加它,只是为了你什么时候应该决定注入一些东西。
从 Angular 2.2.3
开始,现在有一个 forwardRef()
实用程序函数,允许您注入尚未定义的提供程序。
通过未定义,我的意思是依赖注入映射不知道标识符。这就是循环依赖期间发生的情况。您可以在 Angular 中拥有很难解开和查看的循环依赖关系。
export class HeaderComponent {
mobileNav: boolean = false;
constructor(@Inject(forwardRef(() => MobileService)) public ms: MobileService) {
console.log(ms);
}
}
将 @Inject(forwardRef(() => MobileService))
添加到原始问题源代码中构造函数的参数将解决问题。
参考
Forward references in Angular 2
forwardRef()
已经存在于 alpha 中;-) 只有在同一文件中进一步声明了 Mobile
服务时才需要它。如果类在不同的文件中,则不需要 forwardRef()
forwardRef()
确实有助于摆脱 Can't resolve all parameters for ...
消息。至少该组件正在工作,而我正在寻找更好的问题解决方案。 (是的,失败的依赖项是直接从其文件中导入的)
forwardRef
的结果。很难找到。昨天花了我一整天来解决这个问题。
foreardRef
但在引入 NgModule
后不再使用的答案。我不担心失去代表。我只是好奇你为什么在几个月后不再出现这个问题后遇到这个问题。过几天我回家再仔细看看。非常感谢您的反馈。
错误#1:忘记装饰器:
//Uncaught Error: Can't resolve all parameters for MyFooService: (?).
export class MyFooService { ... }
错误#2:省略“@”符号:
//Uncaught Error: Can't resolve all parameters for MyFooService: (?).
Injectable()
export class MyFooService { ... }
错误#3:省略“()”符号:
//Uncaught Error: Can't resolve all parameters for TypeDecorator: (?).
@Injectable
export class MyFooService { ... }
错误#4:小写“i”:
//Uncaught ReferenceError: injectable is not defined
@injectable
export class MyFooService { ... }
错误#5:你忘了: import { Injectable } from '@angular/core';
//Uncaught ReferenceError: Injectable is not defined
@Injectable
export class MyFooService { ... }
正确的:
@Injectable()
export class MyFooService { ... }
如前所述,该问题是由循环依赖引起的桶内的导出排序引起的。
更详细的解释在这里:https://stackoverflow.com/a/37907696/893630
我通过将服务 A 注入服务 B 也遇到了这种情况,反之亦然。
我认为这很快失败是一件好事,因为无论如何都应该避免它。如果您希望您的服务更加模块化和可重用,最好尽可能避免循环引用。此 post 突出了围绕它的陷阱。
因此,我有以下建议:
如果您觉得类交互过于频繁(我说的是功能嫉妒),您可能需要考虑将 2 个服务合并为 1 个类。
如果上述方法对您不起作用,请考虑使用第三个服务(一个 EventService),两个服务都可以注入该服务以交换消息。
为了搜索者的利益;我得到了这个错误。这只是一个缺少的@符号。
即这会产生 Can't resolve all parameters for MyHttpService
错误。
Injectable()
export class MyHttpService{
}
添加缺少的 @
符号可以修复它。
@Injectable()
export class MyHttpService{
}
另一种可能性是在 tsconfig.json 中没有将 emitDecoratorMetadata
设置为 true
{
"compilerOptions": {
...
"emitDecoratorMetadata": true,
...
}
}
除了缺少的 @Injectable()
装饰器
抽象类中缺少 @Injectable()
装饰器导致无法解析服务的所有参数:(?) 装饰器需要存在于 MyService
以及派生类 BaseService
中
//abstract class
@Injectable()
abstract class BaseService { ... }
//MyService
@Injectable()
export class MyService extends BaseService {
.....
}
就我而言,我需要将 import "core-js/es7/reflect";
添加到我的应用程序以使 @Injectable
工作。
如果您的服务 A 依赖于服务 B 的静态属性/方法,并且服务 B 本身通过依赖注入依赖于服务 A,则会出现此错误。所以它是一种循环依赖,尽管它不是因为属性/方法是静态的。可能是与 AOT 结合使用的错误。
A -> B
并且他们都使用相同的静态类。 forwardRef
的解决方案会有所帮助,但我将看看如何解决这个问题。我可能会尝试从这个静态类中创建一个真正的服务(这也会带来更好的设计)。
就我而言,这是因为我没有声明构造函数参数的类型。
我有这样的事情:
constructor(private URL, private http: Http) { }
然后将其更改为下面的代码解决了我的问题。
constructor(private URL : string, private http: Http) {}
This answer 可能对这个问题很有帮助。此外,就我而言,将服务导出为 default
是原因。
错误的:
@Inject()
export default class MobileService { ... }
正确的:
@Inject()
export class MobileService { ... }
对我来说,@Injectable 中缺少 ()
。正确的是@Injectable()
从可注入构造函数()方法中删除参数解决了我的情况。
就我而言,这是因为插件 Augury,禁用它会正常工作。替代选项是aot,也可以。
所有功劳归于@Boboss74,他在这里发布了答案:https://github.com/angular/angular/issues/23958
对我来说,这个问题更烦人,我在一个服务中使用一个服务,却忘记将它作为依赖项添加到 appModule 中!希望这可以帮助某人节省几个小时分解应用程序只是为了重新构建它
@Inject
注释。我忽略了错误消息所说的内容。如果您不怀疑循环依赖,只需转到错误中提到的类并查看所有构造函数参数和任何带有 @Inject
注释的类成员,并确保您对所有这些都进行了正确的 DI。更多关于 DI 的信息:angular.io/docs/ts/latest/guide/dependency-injection.html
由于错误中缺乏反馈,这可能是一个非常难以调试的问题。如果您担心实际的循环依赖,这里是堆栈跟踪中最重要的内容 a) 服务的名称 b) 该服务中带有问号的构造函数参数,例如,如果它看起来像这样:
无法解析 AuthService 的所有参数:([object Object], [object Object], [object Object], [object Object], ?)
那么这意味着第 5 个参数是一个也依赖于 AuthService 的服务。即问号,表示它没有被 DI 解决。
从那里,您只需要通过重构代码来解耦这 2 个服务。
添加 Injectable 解决了我的问题:
错误代码
import { Observable } from 'rxjs';
import { io } from 'socket.io-client';
import { HttpClient } from '@angular/common/http';
export class Chat {
修复后
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { io } from 'socket.io-client';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class Chat {
我通过输入错误的服务名称遇到此错误,即构造函数(私有 myService:MyService)。
对于拼写错误的服务,我可以通过检查 Chrome->Console 中的页面来确定哪个服务是问题(我在构造函数中列出了几个)。您将通过显示对象对象、对象对象、? (或类似的东西)。注意“?”在哪里是,这就是导致问题的服务的位置。
您必须在 @Component 装饰器或声明组件的模块中添加提供者数组。在组件内部,您可以执行以下操作:
@Component({
moduleId: module.id,
selector: 'pm-header',
templateUrl: 'header.component.html',
styleUrls: ['header.component.css'],
directives: [ROUTER_DIRECTIVES, NgClass],
providers: [MobileService]
})
在我的例子中,将错误的参数传递给构造函数会产生这个错误,关于这个错误的基本想法是你在不知不觉中将一些错误的参数传递给了任何函数。
export class ProductComponent {
productList: Array<Product>;
constructor(productList:Product) {
// productList:Product this arg was causing error of unresolved parameters.
this.productList = [];
}
}
我通过删除那个论点解决了这个问题。
对我来说,当我在 polyfills.ts 文件中错误地禁用了这个导入时,我得到了这个错误,你需要确保它被导入以避免这个错误。
/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import 'core-js/es7/reflect';
就我而言,我试图扩展“NativeDateAdapter
”以覆盖“format(date: Date, displayFormat: Object)
”方法。
在 AngularMaterial-2 DatePicker 中。
所以基本上我忘了添加 @Injectable
注释。
在我将它添加到我的“CustomDateAdapter”类之后:
@Injectable({
providedIn: 'root'
})
错误消失了。
明白了!
如果上述答案都没有帮助您,那么您可能正在从组件注入服务的同一个文件中导入一些元素。
我解释得更好:
这是服务文件:
// your-service-file.ts
import { helloWorld } from 'your-component-file.ts'
@Injectable()
export class CustomService() {
helloWorld()
}
这是组件文件:
@Component({..})
export class CustomComponent {
constructor(service: CustomService) { }
}
export function helloWorld() {
console.log('hello world');
}
因此,即使符号不在同一个组件内,而只是在同一个文件内,它也会导致问题。将符号(它可以是函数、常量、类等等)移到别处,错误就会消失
对于 Angular 6 和更新版本,请尝试
@Injectable({
providedIn: 'root'
})
..就在您的服务等级之上,中间没有其他线条
优点
无需将服务添加到任何模块(将“自动发现”)
服务将是一个单例(因为它将被注入到根中)
尽管可能已经提到了从桶中导出类的顺序,但以下场景也可能产生相同的效果。
假设您有从 A
依赖于 B
和 C
的同一文件中导出的类 A
、B
和 C
:
@Injectable()
export class A {
/** dependencies injected */
constructor(private b: B, private c: C) {}
}
@Injectable()
export class B {...}
@Injectable()
export class C {...}
由于 Angular 尚不知道 依赖 类(即在本例中为类 B
和 C
),(可能在运行时 Angular 对类 {3 的依赖注入过程中) }) 引发错误。
解决方案
解决方案是在 DI 完成的类之前声明和导出依赖类。
即在上述情况下,类 A
在其依赖项定义后立即声明:
@Injectable()
export class B {...}
@Injectable()
export class C {...}
@Injectable()
export class A {
/** dependencies injected */
constructor(private b: B, private c: C) {}
}
在我的例子中,我从同一个组件文件中导出了一个类和一个枚举:
mComponent.component.ts
:
export class MyComponentClass{...}
export enum MyEnum{...}
然后,我尝试使用 MyComponentClass
的子级的 MyEnum
。这导致无法解析所有参数错误。
通过将 MyEnum
从 MyComponentClass
移到单独的文件夹中,解决了我的问题!
正如 Günter Zöchbauer 所说,这是因为服务或组件是循环依赖的。
如果您的服务与组件(使用它)在同一个文件中定义,并且服务是在文件中的组件之后定义的,您可能会收到此错误。这是由于其他人提到的相同的“forwardRef”问题。目前 VSCode 不能很好地向您显示此错误并且构建成功编译。
由于编译器的工作方式(可能与摇树相关),使用 --aot
运行构建可以掩盖此问题。
解决方案:确保服务定义在另一个文件中或在组件定义之前。 (我不确定在这种情况下是否可以使用 forwardRef,但这样做似乎很笨拙)。
如果我有一个非常简单的服务,它与一个组件(有点像视图模型)紧密相关 - 例如。 ImageCarouselComponent
,我可以将其命名为 ImageCarouselComponent.service.ts
,以免它与我的其他服务混淆。
就我而言,这是一个循环引用。我让 MyService 调用 Myservice2 和 MyService2 调用 MyService。
不好 :(
不定期副业成功案例分享
2.0.2
中不是问题)。我发现桶仍然有用,特别是当我需要在不同模块之间导入多个模型和服务时。当它不起作用时,这个import { cleanValues, getState, FirebaseService, NotificationService, ... } from '../../shared/services';
很痛苦(;NgModule
对单例服务没有帮助......