I have a use case in my application:
There is an ApiModule
, there are 2 services in it, both are scoped to the module itself. One is ApiRouteService
and the other one is ApiRouteLoaderService
. Now for the purpose:
ApiRouteService
: It maintains a cache of api routes (route method, name, url etc) and returns an api route object identified by name when asked for it.ApiRouteLoaderService
: It just loads the raw api routes and parses them to be used byApiRouteService
.
The modules in my application are lazy loaded. Now here's the scenario:
When the AuthModule
is lazy loaded. It will import the ApiModule.forFeature(AuthApiRoutes)
. The forFeature
method looks like:
@NgModule({
imports: [CommonModule],
providers: [ApiRouteService, ApiRouteLoaderService],
})
export class ApiModule {
public static forFeature(apiRoutes: Array<IRawApiRoute>): ModuleWithProviders<ApiModule> {
return {
ngModule: ApiModule,
providers: [
{
provide: ApiRouteService,
useFactory: (apiRouteLoaderService: ApiRouteLoaderService, apiRouteService: ApiRouteService) => {
const parsedApiRoutes = apiRouteLoaderService.loadRoutes(apiRoutes);
// Now I need the singleton instance of ApiRouteService, so I can call
// apiRouteService.registerRoutes(parsedApiRoutes); and it will add the routes in
// apiRouteService instance along others.
// But I can't call the above, because I need the initial instance of ApiRouteService
// Also note that this function will be called only once when ApiModule is loaded
// in any module
},
deps: [ApiRouteLoaderService, ApiRouteService /* <-- This ApiRouteService causes circular loop */],
},
],
};
}
}
How I can achieve this? Is there a better way to do it?
CodePudding user response:
Maybe I am misunderstanding what you want to do, but it looks like you just need to call apiRouteLoaderService.loadRoutes
and apiRouteService.registerRoutes
on module initialization. I don't think you actually want to provide another instance of the ApiRouteService
do you? If that is the case I would just provide the apiRoutes
, inject the dependencies and call the methods like this:
export const ROUTES = new InjectionToken<Array<IRawApiRoute>>('routes');
@NgModule({
imports: [CommonModule],
providers: [ApiRouteService, ApiRouteLoaderService],
})
export class ApiModule {
constructor(
private apiRouteService: ApiRouteService,
private apiRouteLoaderService: ApiRouteLoaderService,
@Inject(ROUTES) @Self() @Optional() private routes?: Array<IRawApiRoute>
) {
if(routes) {
const parsedApiRoutes = this.apiRouteLoaderService.loadRoutes(routes);
this.apiRouteService.registerRoutes(parsedApiRoutes);
}
}
public static forFeature(apiRoutes: Array<IRawApiRoute>): ModuleWithProviders<ApiModule> {
return {
ngModule: ApiModule,
providers: [{
provide: ROUTES,
useValue: apiRoutes,
}],
};
}
}