当我尝试在Angular 10中使用库中的服务时,“无法解析服务的所有参数:?”

问题描述

在我的图书馆中,我使用以下代码提供服务:

import { Inject,Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DataInjectorModule } from '../../data-injector.module';

// @dynamic
@Injectable()
export class RemoteDataService<T> {
  @Inject('env') private environment: any = {};
  public type: new () => T;
  
  constructor(
    model: T,) {
    this.http = DataInjectorModule.InjectorInstance.get(HttpClient);
  }

  // ...
}

data-injector.module(现有原因仅是避免循环依赖):

import { NgModule,Injector } from '@angular/core';

// @dynamic
@NgModule({
  declarations: [],imports: [],providers: [],exports: [],})
export class DataInjectorModule {
  static InjectorInstance: Injector;

  constructor(injector: Injector) {
    DataInjectorModule.InjectorInstance = injector;
  }

}

在我的图书馆的主模块文件中:

import { ModuleWithProviders } from '@angular/compiler/src/core';
import { NgModule,Injector } from '@angular/core';
import { DataInjectorModule } from './data-injector.module';
import { RemoteDataService } from './services/remote-data/remote-data.service';

// @dynamic
@NgModule({
  declarations: [],imports: [
    DataInjectorModule,],})
export class DataCoreModule {
  static InjectorInstance: Injector;

  constructor(injector: Injector) {
    DataCoreModule.InjectorInstance = injector;
  }

  public static forRoot(environment: any): ModuleWithProviders {
    return {
      ngModule: DataCoreModule,providers: [
        RemoteDataService,{ provide: 'env',useValue: environment }
      ]
    };
  }
}

最后在我应用程序的app.module.ts中:

import { browserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { DataCoreModule } from 'data-core';

import { AppRoutingModule } from './app-routing.module';
import { environment } from 'src/environments/environment';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent,imports: [
    browserModule,AppRoutingModule,DdataCoreModule.forRoot(environment),bootstrap: [AppComponent]
})
export class AppModule { }

构建进展顺利,但在浏览器中出现此错误

Error: Can't resolve all parameters for RemoteDataService: (?).
    at getUndecoratedInjectableFactory (core.js:11338)
    at injectableDefOrInjectorDefFactory (core.js:11328)
    at providerToFactory (core.js:11371)
    at providerToRecord (core.js:11358)
    at R3Injector.processprovider (core.js:11256)
    at core.js:11230
    at core.js:1146
    at Array.forEach (<anonymous>)
    at deepForEach (core.js:1146)
    at R3Injector.processInjectorType (core.js:11230)

我在StackOverflow中检查了关于此主题的几个问题,例如this,但是几乎所有地方都只缺少@Injectable(),但是在这种情况下,我使用了这种装饰器。

有什么主意我该如何解决这个问题?

解决方法

错误:无法解析RemoteDataService的所有参数:(?)

错误说明了一切。 Angular无法解析RemoteDataService中的所有构造函数参数。实例化此服务后,它将需要必需的参数。

您可以通过InjectionToken提供所需的依赖关系,有关详细信息,请参见this答案。

但是您的服务使用generics,并且您没有提到如何在组件中使用此服务,因此建议您在组件中声明提供程序(或模块也可以使用)并使用{ {1}}可以在您的组件中注入该服务的不同版本,如下所示(签出this StackBlitz并查看控制台中来自服务构造函数的日志)-

@Inject()

此外,不确定是否可以在构造函数外部使用import { Component,Inject } from "@angular/core"; import { RemoteDataService } from "./custom/remote-data.service"; export class A {} export class B {} @Component({ selector: "my-app",templateUrl: "./app.component.html",styleUrls: ["./app.component.css"],providers: [ { provide: "env",useValue: {} },{ provide: "ARemoteDataService",useFactory: () => new RemoteDataService<A>(new A()) },{ provide: "BRemoteDataService",useFactory: () => new RemoteDataService<B>(new B()) } ] }) export class AppComponent { constructor( @Inject("ARemoteDataService") private aRemoteDataService: RemoteDataService<A>,@Inject("BRemoteDataService") private bRemoteDataService: RemoteDataService<B> ) {} } 。但是,您始终可以使用注入器来获取其他依赖项(在您的情况下为@Inject())-

env

}

,

我找到了解决方案(实际上是一种解决方法)。我认为这不是一种优雅的方法,但是很容易。

我创建了一个EnvService类,该类可以从模块中获取environment参数,并且没有构造函数属性的副作用:

import { Inject,Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',})
export class EnvService {
  public environment: any = {};

  constructor(@Inject('env') private env?: any) {
    this.environment = env ?? {};
  }
}

然后在库的主模块文件中设置EnvService而不是RemoteDataService

import { ModuleWithProviders } from '@angular/compiler/src/core';
import { NgModule,Injector } from '@angular/core';
import { DataInjectorModule } from './data-injector.module';
import { EnvService } from './services/env/env.service';

// @dynamic
@NgModule({
  declarations: [],imports: [
    DataInjectorModule,],providers: [],exports: [],})
export class DataCoreModule {
  static InjectorInstance: Injector;

  constructor(injector: Injector) {
    DataCoreModule.InjectorInstance = injector;
  }

  public static forRoot(environment: any): ModuleWithProviders {
    return {
      ngModule: DataCoreModule,providers: [
        EnvService,{ provide: 'env',useValue: environment }
      ]
    };
  }
}

最后,在我的RemoteDataService中,将@Inject解决方案更改为InjectorInstance.get(EnvService)解决方案:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DataInjectorModule } from '../../data-injector.module';
import { EnvService } from '../env/env.service';

// @dynamic
@Injectable()
export class RemoteDataService<T> {
  private env = DdataInjectorModule.InjectorInstance.get(EnvService);
  public type: new () => T;
  
  constructor(
    model: T,) {
    this.http = DataInjectorModule.InjectorInstance.get(HttpClient);
  }

  // ...
}

因此RemoteDataService的{​​{1}}属性没有受到影响,但是服务可以通过constructor访问环境变量。

,

在大多数情况下,角度DI是在library(shiny) ui <- fluidPage( # here actionButton("button","Faça Login e assine") ) server <- function(input,output,session) { observeEvent(input$button,{ ## do something }) } shinyApp(ui,server) 中完成的。正如您这样编写构造函数

constructor

Angular认为您正在尝试注入constructor( model: T,) 。您应该将所有想要的东西注入到构造函数中

T

,但是请确保正确提供了env。甚至出于这个原因最好使用constructor( @Inject('env') private environment) {}