Angular-通用服务提供商 [英] Angular - Providers for generic services

查看:87
本文介绍了Angular-通用服务提供商的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经为我的HTTP API创建了通用服务,并且我想为不同的端点提供此服务,而无需为每个端点创建类.我的服务看起来像这样

I have created a generic service for my HTTP APIs and I want to provide this service for different endpoint without creating a class for each of my endpoints. My service looks like this

export class ApiService<T> {
  constructor(private httpClient: HttpClient, private otherDependency: OtherDependency, private subPath: string, private defaultHeaders = []) { }
}

我正在使用令牌和像这样的提供者注入它

And I am injecting it using tokens and providers like these ones

import { InjectionToken } from '@angular/core';

export const XXXToken = new InjectionToken<ApiService<XXX>('MyService');
export const XXXProvider = {
  provide: XXXToken,
  useFactory: (httpClient: HttpClient, dep: OtherDependency) => new ApiService<XXX>(httpClient, dep, 'xxx'),
  deps: [ HttpClient, OtherDependency]
};

当尝试在NgModule的声明中使用我的提供程序并在生产模式下构建(仅在生产模式下)时,先前的代码实际上将失败.错误看起来像

Previous code will actually fail when trying to use my provider in the declarations of a NgModule and building in production mode (only in production mode). Error looks like

 Error during template compile of 'AppModule'
 Consider changing the function expression into an exported function.

问题来自(httpClient:HttpClient,dep:OtherDependency)=>新的ApiService< XXX>(httpClient,dep,'xxx')

如果我做类似的事情,我就可以使它工作

I can make it work if I do something like

export function myFactory(httpClient: HttpClient, dep: OtherDependency) => new ApiService<XXX>(httpClient, dep, 'xxx');
export const XXXProvider = {
  provide: XXXToken,
  useFactory: myFactory,
  deps: [ HttpClient, OtherDependency]
};

但是,因为提供者和工厂比这要复杂得多,所以我创建了一个辅助函数,使我每次添加新端点时都不必重复该代码.

However, because the provider and factory is more complicated than that, I've created an helper function to not have to repeat that code any time I am adding a new endpoint.

export func getProvider(token, subPath) {
  return {
    provide: token,
  useFactory: (httpClient: HttpClient, dep: OtherDependency) => new ApiService<XXX>(httpClient, dep, subPath),
  deps: [ HttpClient, OtherDependency]
  }
}

并且在那里我不能使用导出功能技巧,因为我希望每次创建新服务时子路径都不同.

And in there I cannot use the export function trick because I want my subpath to be different everytime I am creating a new service.

是否有解决此问题的方法,还是我每次需要重复创建提供程序时都会坚持下去.我会很难过,因为这意味着,例如,当我需要对该服务的新依赖性时,我将不得不更改每个提供程序的创建.===编辑===我希望能够轻松地将我的服务注入到任何服务/组件中,而不必将那些其他对象与服务创建或实现细节进行绑定,并且一个组件中可以包含许多服务.理想情况下,我想要这样的东西

Is there a way to get around this or am I stuck to repeating my provider creation every time I need it. I would be very sad since that would mean for example that I would have to change every provider creation anytime I need a new dependency on that service. === Edit === I want to be able to inject my services easily in any service/component without having to bin those other objects to the service creation or implementation detailes and there can be many services in one component. Ideally I would like something like that

export class MyComponent implements OnInit {
  constructor(private userService: ApiService<User>, private countryService: ApiService<countryService>) { }

  ngOnInit() {
    userService.get();
    countryService.get();
  }
}

但是因为javascript并不真正支持泛型,所以这不能工作,因为ApiService和ApiService实际上是同一类.因此,无论如何我目前都需要注入令牌,所以我可以接受

But because javascript does not realy support generics, this cannot work because ApiService and ApiService are actually the same class. Therefore I currently need injection token anyway so I would be OK with

export class MyComponent implements OnInit {
  constructor(@Inject(UserToken) private userService: ApiService<User>, @Inject(CountryToken) private countryService: ApiService<countryService>) { }

推荐答案

,因为您希望为不同的端点提供相同的服务,因此需要将端点配置作为 InjectionToken 进行提供,然后将该令牌注入您的服务会让您的生活更轻松.因此,请如下更改服务定义;

since you want to provide same service with different end points, providing your end point config as an InjectionToken and injecting that token in your service would make your life easier. so change your service definition as follows;

export const MY_API_ENDPOINT = new InjectionToken<string>('MY_API_ENDPOINT');

@Injectable()
export class ApiService<T> {
  constructor(@Inject(MY_API_ENDPOINT) private endPoint: string) { }
}

在通过整个应用程序注入 ApiService 时,请在提供程序级别配置 MY_API_ENDPOINT (无论是组件级别还是模块级别)

when you inject ApiService through out your application, configure MY_API_ENDPOINT at provider level (doesn't matter whether it is at Component or Module level)

在组件级别

@Component({
  selector: 'app-component1',
  templateUrl: './component1.component.html',
  styleUrls: ['./component1.component.css'],
  providers: [ApiService, { provide: MY_API_ENDPOINT, useValue: "api.end.point.1" }]
})
export class Component1Component implements OnInit {}

或在模块级别

@NgModule({
  imports: [CommonModule],
  declarations: [Component3Component],
  exports: [Component3Component],
  providers: [ApiService, { provide: MY_API_ENDPOINT, useValue: "api.end.point.3" }]
})
export class App2Module { }

我创建了一个演示,演示了具有不同端点的组件级和模块级提供程序

i created a demo that demonstrates both Component and Module level providers with different endpoints

https://stackblitz.com/edit/angular-4b5yb7

=====第二个解决方案=====

上述解决方案将不起作用.因此,我们需要一种创建具有不同参数的相同服务实例的方法.遵循创建工厂创建服务实例的原始方法;我修改了工厂函数,该函数返回一个以endPoint作为参数的函数,并且该函数创建具有唯一endPoints的实例.

above solution will not work if a component needs same service with two different end points. so we need a way to create same service instances with different parameters. following you original approach of creating a factory that creates service instances; i modified the factory function that returns a function which takes endPoint as parameter, and that function creates instances with unique endPoints.

{
    provide: ApiService, useFactory:
      (someOtherService: SomeOtherService) => {
        return (endPoint: string) => {
          return new ApiService(endPoint, someOtherService);
        }
      }, deps: [SomeOtherService /** this is just an example to show how to inject other dependencies*/]
}

并在组件中按如下所述使用它

and use it as follows in component

export class Component1Component {
  apiService1 = this.apiFactory<string>("end.point.1");
  apiService2 = this.apiFactory<number>("end.point.2");

  constructor(@Inject(ApiService) private apiFactory: <T>(endPoint: string) => ApiService<T>) {}
}

这是一个工作示例 https://stackblitz.com/edit/angular-6kmy8w

ps.我从这篇文章中得到了这个主意.我改进了打字和合并的更改,以使服务具有通用性

ps. i got the idea from this post. i improved typing and incorporated changes for making the service generic

这篇关于Angular-通用服务提供商的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆