4

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

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,
  ],
  providers: [],
  exports: [],
})
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),
  ],
  providers: [],
  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 中检查了关于这个主题的几个问题,就像这样,但几乎在所有地方都只是@Injectable()缺少的部分,但在这种情况下,我使用了这个装饰器。

知道如何解决这个问题吗?

4

3 回答 3

3

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

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

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

但是您的服务使用generics并且您没有提及您如何在组件中使用此服务,所以我建议您在组件中声明提供程序(或模块也可以工作)并用于@Inject()在您的如下所示的组件(查看此 StackBlitz并查看控制台以获取来自服务构造函数的日志)-

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在您的情况下)-

// @Inject('env') private environment: any = {};
constructor(model: T) {
this.environment = DataInjectorModule.InjectorInstance.get("env");

}

于 2020-10-21T18:22:04.480 回答
2

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

我创建了一个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's 的constructor属性是不变的,但是服务可以通过EnvService.

于 2020-10-21T18:55:18.937 回答
1

Angular DIconstructor在大多数情况下都会完成。正如您这样编写构造函数

constructor(
    model: T,
  )

Angular 认为您正在尝试注入T. 你应该在构造函数中注入你想要的所有东西

constructor( @Inject('env') private environment) {}

但请确保正确提供了 env。InjectionToken出于这个原因,甚至更好地使用s

于 2020-10-20T23:00:50.000 回答