【问题标题】:Error when trying to inject a service into an angular component "EXCEPTION: Can't resolve all parameters for component", why?尝试将服务注入角度组件时出错“例外:无法解析组件的所有参数”,为什么?
【发布时间】:2016-10-26 03:41:50
【问题描述】:

我已经在 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(桶)吗?您可以尝试从直接声明它的文件中导入它吗?
  • 奇迹般地修复了它!奇怪的是,当我使用其他组件测试服务时,它无法使用桶。如果您想将其发布为答案而不是评论,我会接受。
  • 一般是循环依赖。
  • 我也遇到过循环依赖的问题。值得注意的是,较新版本的 webpack 更能告诉你这一点
  • 看起来像循环依赖,如果你使用 angular >=4 这样你就可以摆脱 intex.ts (barrel) 并直接导入你需要的所有东西。

标签: angular typescript dependency-injection


【解决方案1】:

从直接声明它的文件中导入,而不是从桶中导入。

我不知道究竟是什么导致了这个问题,但我看到它多次提到(可能是某种循环依赖)。

它也应该可以通过改变桶中出口的顺序来解决(不知道细节,但也提到过)

【讨论】:

  • 这是正确的,例如,如果您将一个服务注入到另一个服务中,而第一个服务需要首先进入桶中。
  • Angular2 团队不再推荐桶,因为有很多这样的问题。很高兴听到我能帮忙:)
  • 不知道 Angular 2 团队不推荐桶。如果是这样,他们应该注意到在讨论他们的好处的glossary 中。像angular2-webpack-starter 这样的项目不应该使用它们。
  • 它接缝这是固定的(在2.0.2 中不是问题)。我发现桶仍然有用,特别是当我需要在不同模块之间导入多个模型和服务时。这个import { cleanValues, getState, FirebaseService, NotificationService, ... } from '../../shared/services'; 不起作用时很痛苦(;NgModule 对单例服务没有帮助......
  • Argghh 我通过更改桶(index.ts)文件中的导出顺序解决了这个问题。非常感谢
【解决方案2】:

如前所述,问题是由循环依赖引起的桶内的导出排序引起的。

更详细的解释在这里:https://stackoverflow.com/a/37907696/893630

【讨论】:

  • 订购没有解决我的问题。没有使用枪管。
【解决方案3】:

除了之前给出的答案之外,当您的可注入服务缺少实际的 @Injectable() 装饰器时,似乎也会引发此错误。因此,在调试循环依赖项和导入/导出顺序之前,请先简单检查一下您的服务是否确实定义了 @Injectable()

这适用于当前最新的 Angular,Angular 2.1.0。

I opened an issue on this matter.

【讨论】:

  • 是的,这个错误通常是因为你忘记添加@Injectable,例如你可能只是从'@angular/router'导入Router,没有那个可注入的,这个错误总是会发生(一旦你决定让一行代码使用注入的路由器。
  • 很棒的答案,我的问题是我在服务中添加了一个方法,并且没有在最后一个大括号后添加分号。我不知道为什么它必须是这种方式,但在组件类中并非如此......现在我很高兴继续前进!
  • 我有一个简单的模型给了我这个错误。我使用了在模型的构造函数中创建属性的快捷方式。属性的类型只有 string 和 int。然后突然这个问题开始发生。添加 @Injectable() 解决了这个问题。很奇怪,因为我的其他模型都没有添加 Injectable。我必须补充一点,在添加这个新模型之前我升级了很多库。可能与它有关,但现在正在工作。谢谢。
  • @Moutono 正确。在您的服务中使用空构造函数时,似乎不会触发依赖注入,并且不需要 @injectable()。这本身就是另一个奇怪之处。为了更好的衡量,我仍然会添加它,只是为了你什么时候应该决定注入一些东西。
  • 请记住,如果您的服务有一个也需要用@Injectable() 修饰的基类
【解决方案4】:

我通过将服务 A 注入服务 B 也遇到了这种情况,反之亦然。

我认为这很快失败是一件好事,因为无论如何都应该避免这种情况。如果您希望您的服务更加模块化和可重用,最好尽可能避免循环引用。这个post 突出了围绕它的陷阱。

因此,我有以下建议:

  • 如果您觉得类交互过于频繁(我说的是feature envy),您可能需要考虑将 2 个服务合并为 1 个类
  • 如果上述方法不适合您,请考虑使用两个服务都可以注入的第三个服务EventService)以交换消息。

【讨论】:

  • 这绝对是发生在我身上的事情,这就是要走的路。如果您知道有多个服务需要更新,请使用 EventService。它更具可扩展性,因为当您基于这些事件扩展应用程序时,您无疑必须利用这些事件。
【解决方案5】:

从 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))添加到原问题源代码中构造函数的参数即可解决问题。

参考文献

Angular 2 Manual: ForwardRef

Forward references in Angular 2

【讨论】:

  • forwardRef() 已经存在于 alpha 中;-) 仅当在同一文件中进一步声明 Mobile 服务时才需要它。如果类在不同的文件中,则不需要forwardRef()
  • Günter Zöchbauer,我仍在尝试找出我的代码的真正问题,但与此同时,forwardRef() 确实帮助摆脱了Can't resolve all parameters for ... 消息。至少该组件正在工作,而我正在寻找更好的问题解决方案。 (是的,失败的依赖是直接从其文件中导入的)
  • @GünterZöchbauer 我已经用参考更新了我的答案。我不是想从您的答案中删除,但这实际上解决了问题,人们需要了解它。如果你用谷歌搜索这个问题,没有结果表明使用forwardRef。很难找到。昨天花了我一整天来解决这个问题。
  • 很奇怪。我发布了至少十几个答案,建议我自己使用foreardRef,但在引入NgModule 之后不再使用。我不担心失去代表。我只是好奇你为什么在几个月后不再出现这个问题后遇到这个问题。过几天我回家再仔细看看。非常感谢您的反馈。
  • 如果有人也对导入感到迷茫:import { Component, Inject, ForwardRefFn, forwardRef } from '@angular/core';
【解决方案6】:

对我来说,这个问题更烦人,我在服务中使用了一个服务,却忘记将它作为依赖项添加到 appModule 中! 希望这可以帮助某人节省几个小时来分解应用程序,然后重新构建它

【讨论】:

  • 我只是错过了@Inject 注释。我忽略了错误消息所说的内容。如果您不怀疑循环依赖,只需转到错误中提到的类并查看所有构造函数参数和任何使用@Inject 注释的类成员,并确保您对所有这些都进行了正确的 DI。更多关于 DI 的信息:angular.io/docs/ts/latest/guide/dependency-injection.html
【解决方案7】:

我通过输入错误的服务名称遇到此错误,即构造函数(私有 myService: MyService)。

对于拼写错误的服务,我可以通过在 Chrome->Console 中检查页面来确定问题所在(我在构造函数中列出了几个)。您将通过显示对象对象、对象对象、? (或类似的东西)。注意“?”在哪里是,这就是导致问题的服务的位置。

【讨论】:

    【解决方案8】:

    为了搜索者的利益;我得到了这个错误。这只是一个缺少的@符号。

    即这会产生Can't resolve all parameters for MyHttpService 错误。

    Injectable()
    export class MyHttpService{
    }
    

    添加缺少的@ 符号可以修复它。

    @Injectable()
    export class MyHttpService{
    }
    

    【讨论】:

    • 在我的例子中,我在@Injectable 和服务类定义之间添加了额外的类和接口,所以服务类不再被标记为可注入的。
    • 如果你完全忘记了消费其他可注入服务的服务类上的@Injectable() 装饰器,那么你装饰不当的服务也会抛出这个错误。
    【解决方案9】:

    从可注入的 constructor() 方法中删除参数解决了我的情况。

    【讨论】:

    • 这也是我的问题。我是来发帖的,但发现你先发了! +1
    • 那么如何将参数发送到可重用服务?
    【解决方案10】:

    如果您的服务 A 依赖于服务 B静态属性/方法 和服务 ,则会出现此错误B 本身通过依赖注入依赖于服务A。所以它是一种循环依赖,尽管它不是因为属性/方法是静态的。可能是与 AOT 结合出现的错误。

    【讨论】:

    • 当依赖于在同一个文件中简单定义的函数时,我也有它。将其拆分为单独的文件可以修复它。
    • 感谢您提及。我发现自己处于确切的境地。我没有意识到直接访问静态类可能与 DI 有关。我有这个方案:A -> B,他们都使用同一个静态类。 forwardRef 的解决方案有帮助,但我将看看如何解决这个问题。我可能会尝试从这个静态类中创建一个真正的服务(这也会带来更好的设计)。
    【解决方案11】:

    当使用桶进口时 - 作为经验法则,首先考虑进口注射剂。

    【讨论】:

      【解决方案12】:

      在引用 interface 时也会发生这种情况。

      interface 更改为class 修复了它,无论是否使用@Inject

      【讨论】:

        【解决方案13】:

        您必须在 @Component 装饰器或声明组件的模块中添加提供者数组。在组件内部,您可以执行以下操作:

        @Component({
          moduleId: module.id,
          selector: 'pm-header',
          templateUrl: 'header.component.html',
          styleUrls: ['header.component.css'],
          directives: [ROUTER_DIRECTIVES, NgClass],
          providers: [MobileService]
        })
        

        【讨论】:

          【解决方案14】:

          当您在 app.module.js 中声明 Angular 的内置模块(HttpClientModule、HttpErrorResponse 等)时,有时会发生这种情况。我也遇到了同样的问题,但现在解决了。

          我犯的错误是将 HttpClientModule 提到 Providers 而不是 Import 的 angular Module

          【讨论】:

            【解决方案15】:

            就我而言,这是因为我没有声明构造函数参数的类型。

            我有这样的事情:

            constructor(private URL, private http: Http) { }
            

            然后将其更改为下面的代码解决了我的问题。

            constructor(private URL : string, private http: Http) {}
            

            【讨论】:

              【解决方案16】:

              除了缺少的@Injectable()装饰器

              抽象类中缺少 @Injectable() 装饰器会产生无法解析服务的所有参数:(?) 装饰器需要存在于MyService 以及派生类BaseService

              //abstract class
              @Injectable()
              abstract class BaseService { ... }
              
              //MyService    
              @Injectable()
              export class MyService extends BaseService {
              .....
              }
              

              【讨论】:

              • 我就是这种情况。
              【解决方案17】:

              错误 #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:您忘记了: 从“@angular/core”导入 { Injectable };

              //Uncaught ReferenceError: Injectable is not defined
              @Injectable
              export class MyFooService { ... }
              

              正确:

              @Injectable()
              export class MyFooService { ... }
              

              【讨论】:

              • 但这不会变成单例吗?如果我想要每个依赖项上的新实例怎么办?
              【解决方案18】:

              在我的例子中,将错误的参数传递给构造函数会产生这个错误,关于这个错误的基本想法是你在不知不觉中将一些错误的参数传递给了任何函数。

              export class ProductComponent {
                  productList: Array<Product>;
              
                  constructor(productList:Product) { 
                       // productList:Product this arg was causing error of unresolved parameters.
                       this.productList = [];
                  }
              }
              

              我通过删除该参数解决了这个问题。

              【讨论】:

                【解决方案19】:

                对我来说,这是因为我在尝试缩短编译时间时停止使用 -aot 标志。

                 ng serve -aot
                

                【讨论】:

                  【解决方案20】:

                  虽然可能已经提到了从桶中导出类的排序,但以下场景也可能产生相同的效果。

                  假设您有类ABC 从同一文件中导出,其中A 依赖于BC

                  @Injectable()
                  export class A {
                      /** dependencies injected */
                      constructor(private b: B, private c: C) {}
                  }
                  
                  @Injectable()
                  export class B {...}
                  
                  @Injectable()
                  export class C {...}
                  

                  由于 Angular 尚不知道 依赖 类(即在本例中为 BC 类),(可能在运行时 Angular 的依赖注入过程中class A) 引发错误。

                  解决方案

                  解决办法是在做DI的类之前声明和导出依赖类。

                  即在上述情况下,类 A 是在定义其依赖项之后立即声明的:

                  @Injectable()
                  export class B {...}
                  
                  @Injectable()
                  export class C {...}
                  
                  @Injectable()
                  export class A {
                      /** dependencies injected */
                      constructor(private b: B, private c: C) {}
                  }
                  

                  【讨论】:

                    【解决方案21】:

                    对我来说,这是因为我的 @Component 装饰器和我的 Component 类之间有一个空行。这导致装饰器无法应用于该类。

                    【讨论】:

                      【解决方案22】:

                      另一种可能性是在 tsconfig.json 中没有将 emitDecoratorMetadata 设置为 true

                      {
                        "compilerOptions": {
                      
                           ...
                      
                          "emitDecoratorMetadata": true,
                      
                           ...
                      
                          }
                      
                      }
                      

                      【讨论】:

                        【解决方案23】:

                        在我的例子中,我是从同一个组件文件中导出一个类和一个枚举:

                        mComponent.component.ts:

                        export class MyComponentClass{...}
                        export enum MyEnum{...}
                        

                        然后,我试图从MyComponentClass 的孩子那里使用MyEnum。这导致了 Can't resolve all parameters 错误

                        通过将MyEnum 移动到与MyComponentClass 不同的文件夹中,解决了我的问题!

                        正如 Günter Zöchbauer 所说,这是因为服务或组件是循环依赖的。

                        【讨论】:

                          【解决方案24】:

                          就我而言,我需要将import "core-js/es7/reflect"; 添加到我的应用程序中以使@Injectable 工作。

                          【讨论】:

                          • 现在是 'core-js/features/reflect'。此外,仅在 JIT (dev) 模式下才需要 polyfill,因此可以使用 webpack 中的动态导入和 'magic cmets' 有条件地加载它。例如: if (process.env.NODE_ENV !== 'production') { import(/* webpackMode: "eager" */ 'core-js/features/reflect').then(() => {}); }。见webpack.js.org/api/module-methods/#magic-comments
                          【解决方案25】:

                          对我来说,@Injectable 中缺少 ()。正确的是@Injectable()

                          【讨论】:

                          • 或者在我的情况下不小心删除了@
                          【解决方案26】:

                          在我的情况下,这是因为插件 Augury,禁用它会正常工作。替代选项是 aot,也可以。

                          全部归功于@Boboss74,他在这里发布了答案:https://github.com/angular/angular/issues/23958

                          【讨论】:

                            【解决方案27】:

                            对我来说,当我在 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';
                            

                            【讨论】:

                              【解决方案28】:

                              在我的例子中,我依赖于一个没有依赖关系的服务,因此我没有向服务类添加 constructor() 函数。我向依赖服务类添加了一个无参数构造函数,一切都开始工作了。

                              【讨论】:

                                【解决方案29】:

                                就我而言,我试图扩展“NativeDateAdapter”以覆盖“format(date: Date, displayFormat: Object)”方法。

                                在 AngularMaterial-2 DatePicker 中。

                                所以基本上我忘了添加@Injectable 注释。

                                在我将它添加到我的“CustomDateAdapter”类之后:

                                @Injectable({
                                  providedIn: 'root'
                                })
                                

                                错误消失了。

                                【讨论】:

                                • 这对我有用,但我不知道为什么。是否需要同时提供服务和通过 DI 接收它的组件在:root 中才能使 DI 工作?
                                【解决方案30】:

                                如果您的服务与组件(使用它)在同一个文件中定义,并且服务是在文件中的组件之后定义的,您可能会收到此错误。这是由于其他人提到的相同的“forwardRef”问题。目前 VSCode 不能很好地向您显示此错误并且构建成功编译。

                                使用--aot 运行构建可以掩盖此问题,这是由于编译器的工作方式(可能与摇晃树有关)。

                                解决方案:确保服务是在另一个文件中或在组件定义之前定义的。 (我不确定在这种情况下是否可以使用 forwardRef,但这样做似乎很笨拙)。

                                如果我有一个非常简单的服务,它与组件非常紧密地联系在一起(有点像视图模型) - 例如。 ImageCarouselComponent,我可以将其命名为 ImageCarouselComponent.service.ts,这样它就不会与我的其他服务混淆。

                                【讨论】:

                                  猜你喜欢
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2015-10-03
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  相关资源
                                  最近更新 更多