将主工程中的服务注入到创建的库中。

9

我正在使用Angular 8。

这个问题只适用于Angular DI(依赖注入)专家。

首先,我创建了一个Angular库,将在许多项目中重复使用。

在这个库中,我创建了一个抽象服务,必须在使用它的项目中进行定义。

我在我的库中定义了一个名为BridgeService的抽象类

在我的主要项目中,我创建一个实现它的BridgeService:(在接下来的行中,我将向您展示抽象的BridgeService)

MainProject > BridgeService:

import { BridgeService as AbstractBridgeService } from 'myLibrary';

@Injectable()
export class BridgeService implements AbstractBridgeService {

    hello(){
        alert('hello Word');
    }
}

MainProject > UsersModule :

import { UsersModule as LibraryUsersModule } from 'myLibrary';

@NgModule({
    imports: [
        CommonModule,
        LibraryUsersModule,
    ],
    //...
    providers: [
        BridgeService
        // some try:
        //{ provide: BridgeService, useClass: BridgeService }
    ],
})
export class UsersModule {

    constructor(private bridgeService: BridgeService){
        this.bridgeService.hello();
    }

}

现在我们需要查看相关的库文件:

库 > bridge.service.ts:

export abstract class BridgeService {
    abstract hello(): void;
}

这个BridgeService必须在UsersModule中定义。

库 > 用户模块:

@NgModule({
    //...
    providers: [
        // My Try:
        { provide: BridgeService, useValue: BridgeService} 
    ],
})
export class UsersModule {

    # my goal is that I can uncomment this piece of code:

    //constructor(private bridgeService: BridgeService){
    //  this.bridgeService.hello();
    //}

}

我希望你只改动以下代码中的两行:

1)在Library的UsersModule提供程序数组中:我想将BridgeService声明为抽象,以便成为通用类型。

2)在项目的UsersModule提供程序数组中:我想定义替换Library UserModule中的抽象的BridgeService的行。

1个回答

13
你需要在你的库中定义一个令牌,就这样。在你的库中,你需要定义令牌和接口:
/** Token to inject the bridge service */
export const BRIDGE_SERVICE_ADAPTER:
    InjectionToken<BridgeServiceAdapter> =
        new InjectionToken<BridgeServiceAdapter>('Bridge service token');

export interface BridgeServiceAdapter {
  hello(): void;
}

在你的库中,你可以像这样注入它:

export class UsersModule {
  constructor(
    @Inject(BRIDGE_SERVICE_ADAPTER) private bridgeService: BridgeServiceAdapter
  ){
    if(!bridgeService) {
      throw new Error('You must provide a bridge adapter');
    }
    this.bridgeService.hello();
  }
}

而在你将要使用该库的应用程序中:

import { BridgeServiceAdapter } from 'myLibrary';

@Injectable({providedIn: 'root'})
export class BridgeService implements BridgeServiceAdapter {
    hello() { alert('hello Word') }
}

...
import { UsersModule as LibraryUsersModule, BRIDGE_SERVICE_ADAPTER } from 'myLibrary';

@NgModule({
    imports: [CommonModule,LibraryUsersModule,...],
    providers: [{ provide: BRIDGE_SERVICE_ADAPTER, useExisting: BridgeService }],
})
export class UsersModule {
  // Obs 1: ok, this seems something you should be encapsulating inside
  //   your library to doesn't have to inject in the dependent projects
  // Obs 2: and, here, in the app, as I created BridgeService decorated
  //   with {providedIn: 'root'}, I can inject the service itself. But
  //   if this wasn't the case, I'd have to inject it using the same notation
  //   used in the library: 
  //   @Inject(BRIDGE_SERVICE_ADAPTER) private bridgeService: BridgeServiceAdapter
  //   This would be necessary if I had decorated my service with
  //
  //   @Injectable() (instead of @Injectable({providedIn: 'root'}))
  //
  //   and provided it globally like this:
  //
  //   { provide: BRIDGE_SERVICE_ADAPTER, useClass: BridgeService }
  //
  //   On the above line, notice "useClass" instead of "useExisting"
  constructor(private bridgeService: BridgeService) {
    this.bridgeService.hello();
  }
}

我认为在你上一节课所写的代码中,在其构造函数中,bridgeService 应该被定义为 BridgeServiceAdapter 类型。你觉得呢? - Med Karim Garali
事实上,由于我在服务装饰器中使用了{providedIn: 'root'},所以在我的应用程序内部直接使用该服务没有问题。我认为我会撤销我的编辑,因为这是这种情况的一个很好的例子。在库中,没有选择:您必须使用@Inject(BRIGE_SERVICE_ADPATER)令牌来注入它。 - julianobrasil
当我使用useClass代替useExisting时,我的服务不是单例的,即使该服务已经被定义为{providedIn: 'root'}。不确定我应该期望什么,但想提出来! - adamdport

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接