将特定服务实例注入一个父组件中组件的多个实例

时间:2017-03-03 16:52:04

标签: angularjs angular service dependency-injection components

我现在正在开展一个非常大的项目,我们正努力让我们的代码尽可能模块化。我们有多个Angular应用程序,并且我们已经创建了一个单独的常用UI组件库和一个API套件,其中包含跨这些应用程序使用的公共服务。

我们在尝试构建需要使用服务的通用组件时遇到了问题。例如,我现在正在处理自动完成组件。该组件应该能够从远程源获取数据,并根据在组件的输入字段中输入的内容过滤结果。

对于一个实例,该实现很容易。我在自动完成组件的构造函数中注入自动完成服务,然后在父级上提供它。这使我可以灵活地在使用服务时更改服务的实现细节,同时仍然能够创建可与定义的接口一起使用的可重用组件。

例如:

我们要定义自动填充组件使用的界面的服务:

@Injectable()
export class AutocompleteService {
  public url: string = 'my-api-default';

  constructor(http: Http) {}

  fetch(): any {
    return this.http.get(this.url);
  }
}

自动完成组件实现:

@Component({
  selector: 'my-autocomplete',
  templateUrl: 'my-autocomplete.component.html'
})
export class MyAutocompleteComponent {
  constructor(private autocompleteService: AutocompleteService) {}

  getData() {
    return this.autocompleteService.fetch();
  }
  ...autocomplete logic...
}

现在我可以定义一个实现自动完成服务的熊服务。我可以将熊服务连接到我的自动完成组件,所以我可以选择我的形式的熊物种。

@Injectable()
export class BearService {
  public url: string = 'bear-url';

  constructor(http: Http){}

  fetch() {
    return this.http.get(this.url);
  }
}

接下来,我定义了使用我的自动完成组件的父级,并提供熊服务来获取我的熊种数据。

@Component({
  selector: 'my-form-component',
  template: `
    <form>
      <my-autocomplete [(ngModel)]="bear"></my-autocomplete>
      <button type="submit">Submit</button>
    </form>
  `,
  providers: [
    {provide: AutocompleteService, useClass: BearService}
  ]
})
export class MyFormComponent {
  ...component logic...
}

到目前为止,这么好。

当我需要构建一个使用多个自动完成组件的大型表单时,我的问题就出现了。我的老板告诉我,我需要在这个表格上有三个自动填充区域,一个用于熊类,一个用于甜菜物种,一个用于太空堡垒加拉太卡。我的第一个想法是这样做:

我定义了服务实例:

@Injectable()
export class BeetsService {
  public url: string = 'beets-url';

  constructor(http: Http){}

  fetch() {
    return this.http.get(this.url);
  }
}

@Injectable()
export class BattleStarGallacticaService {
  public url: string = 'battlestar-gallactica';
  constructor(http: Http){}

  fetch() {
    return this.http.get(this.url);
  }
}

然后我更新父模板和提供者:

@Component({
  selector: 'my-form-component',
  template: `
    <form>
      <my-autocomplete [(ngModel)]="bear"></my-autocomplete>
      <my-autocomplete [(ngModel)]="beet"></my-autocomplete>
      <my-autocomplete [(ngModel)]="battleStarGallactica"></my-autocomplete>
      <button type="submit">Submit</button>
    </form>
  `,
  providers: [
    {provide: AutocompleteService, useClass: BearService},
    {provide: AutocompleteService, useClass: BeetService},
    {provide: AutocompleteService, useClass: BattlestarGalacticaService},
  ]
})
export class MyFormComponent {
  ...component logic...
}

现在我怎么知道哪个自动完成组件使用哪个服务?

我知道我现在拥有的始终使用为AutocompleteService提供的最后一个提供程序,因为这是Angular DI框架的工作原理。

我也知道我不能在此使用多提供商,因为Angular仅为NG_VALIDATORSNG_ASYNC_VALIDATORS定义了多提供商。

那么,有没有人知道如何解决我的问题?我不在乎 问题本身如何解决,但我仍然需要能够:

  1. 定义服务接口
  2. 用户可重用组件中的服务接口
  3. 根据自己的需要创建一个新的服务实例,实现原始界面
  4. 能够在单个父组件中使用不同服务实现来实现相同服务接口的多个组件

1 个答案:

答案 0 :(得分:2)

我会将提供者移动到有选择地应用的指令

@Directive({
  selector: 'my-autocomplete[bear]',
  providers: [{ provide: AutoCompleteService, useClass: BearService}]
})
export class BearDirective {}

@Directive({
  selector: 'my-autocomplete[battlestarGalactica]',
  providers: [{ provide: AutoCompleteService, useClass: BattlestarGalacticaService}]
})
export class BattelstarGalacticaDirective{}

然后像

一样使用它
<form>
  <my-autocomplete bear [(ngModel)]="bear"></my-autocomplete>
  <my-autocomplete bear [(ngModel)]="beet"></my-autocomplete>
  <my-autocomplete battlestarGalactica [(ngModel)]="battleStarGallactica"></my-autocomplete>
  <button type="submit">Submit</button>
</form>

并从MyFormComponent

中删除提供商