我已经为我的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>) { }
答案 0 :(得分:0)
因为您想为不同的端点提供相同的服务,所以将端点配置提供为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作为参数的函数,该函数创建具有唯一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*/]
}
并在组件中按如下所述使用它
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。我是从this post得到这个想法的。我改进了打字方式并合并了更改,以使服务具有通用性