angular - Angular - 通用服务的提供者
问题描述
我为我的 HTTP API 创建了一个通用服务,我想为不同的端点提供这个服务,而不为我的每个端点创建一个类。我的服务看起来像这样
export class ApiService<T> {
constructor(private httpClient: HttpClient, private otherDependency: OtherDependency, private subPath: string, private defaultHeaders = []) { }
}
我正在使用这些令牌和提供程序注入它
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 的声明中使用我的提供程序并在生产模式下构建(仅在生产模式下)时,以前的代码实际上会失败。错误看起来像
Error during template compile of 'AppModule'
Consider changing the function expression into an exported function.
问题来自(httpClient: HttpClient, dep: OtherDependency) => new ApiService<XXX>(httpClient, dep, 'xxx')
如果我做类似的事情,我可以让它工作
export function myFactory(httpClient: HttpClient, dep: OtherDependency) => new ApiService<XXX>(httpClient, dep, 'xxx');
export const XXXProvider = {
provide: XXXToken,
useFactory: myFactory,
deps: [ HttpClient, OtherDependency]
};
但是,因为提供者和工厂比这更复杂,所以我创建了一个辅助函数,以便在添加新端点时不必重复该代码。
export func getProvider(token, subPath) {
return {
provide: token,
useFactory: (httpClient: HttpClient, dep: OtherDependency) => new ApiService<XXX>(httpClient, dep, subPath),
deps: [ HttpClient, OtherDependency]
}
}
在那里我不能使用导出功能技巧,因为我希望每次创建新服务时我的子路径都不同。
有没有办法解决这个问题,或者我是否坚持在每次需要时重复我的提供程序创建。我会非常难过,因为这意味着例如,每当我需要对该服务的新依赖时,我都必须更改每个提供程序的创建。=== 编辑 === 我希望能够轻松地将我的服务注入到任何服务/组件中,而不必将那些其他对象绑定到服务创建或实现细节中,并且一个组件中可以有许多服务。理想情况下,我想要这样的东西
export class MyComponent implements OnInit {
constructor(private userService: ApiService<User>, private countryService: ApiService<countryService>) { }
ngOnInit() {
userService.get();
countryService.get();
}
}
但是因为 javascript 并不真正支持泛型,所以这行不通,因为 ApiService 和 ApiService 实际上是同一个类。因此,无论如何我目前都需要注入令牌,所以我可以接受
export class MyComponent implements OnInit {
constructor(@Inject(UserToken) private userService: ApiService<User>, @Inject(CountryToken) private countryService: ApiService<countryService>) { }
解决方案
因为您想为不同的端点提供相同的服务,所以提供端点配置InjectionToken
并将该令牌注入您的服务将使您的生活更轻松。所以改变你的服务定义如下;
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
在提供程序级别进行配置(无论是在组件级别还是在模块级别)
在组件级别
@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 { }
我创建了一个演示,演示了具有不同端点的组件和模块级别提供程序
https://stackblitz.com/edit/angular-4b5yb7
===== 第二个解决方案 =====
如果组件需要具有两个不同端点的相同服务,则上述解决方案将不起作用。所以我们需要一种方法来创建具有不同参数的相同服务实例。遵循您创建创建服务实例的工厂的原始方法;我修改了工厂函数,它返回一个以 endPoint 作为参数的函数,并且该函数创建具有唯一端点的实例。
{
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*/]
}
并在组件中按如下方式使用
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
附言。我从这篇文章中得到了这个想法。我改进了打字并合并了使服务通用的更改
推荐阅读
- r - 如何清除与 DT 链接的传单地图上的标记?
- asp.net-mvc - Azure Active Directory - 我们无法让您登录。请重试
- django - Django 错误:/new_bid/1 处的 ValueError 无法分配“1”:“Bid.listingid”必须是“列表”实例
- javascript - 尝试更改为 onChange 后,onEdit 触发器中断
- pine-script - Pinescript 没有在较短的时间范围图表上绘制更高分辨率的计算。怎么解决
- amazon-web-services - 在 GraphMappingConfig 中自动填充顶点属性
- sql - 找到那些在不同行中具有不同值的列?
- c# - 需要发送FIN/ACK
- python - 围绕另一个点旋转一个点会产生意想不到的结果
- wpf - 可以在没有 IoC 的情况下使用 MvvmCross Messenger 吗?