(How) is it possible to configure injectors to use a class based on some data available at bootstrap?
I have two implementations for interfacing with the backend, (for simplicity, let's say over http and over websockets).
I created two service classes, backend.http.service
and backend.websocket.service
. They both extend the backend.service
class, so their interface is common.
I'd like my components to inject backend.service
, and be ignorant of which actual interface is in use.
Hardwiring one of the services works like this:
{
provide: BackendService,
useClass: WebsocketBackendService,
},
However I'd like to do something like:
{
provide: BackendService,
useClass: should_i_use_websockets() ? WebsocketBackendService : HttpBackendService,
},
My first guess was to use useFactory
instead (which means I could actually DI some services to calculate which backend to use), but then how would I instantiate the services themselves? Would the factory need to know the exact dependencies of the concrete serivces? That doesn't seem like a nice solution.
{
provide: BackendService,
useFactory: (s: ServiceToDetermineWebsocketAvailability) => {
if (s.should_i_use_websockets()) {
return WebsocketBackendService(???);
} else {
return HttpBackendService(???);
}
}
@Injectable({ providedIn: 'root'})
export abstract class BackendService {
connected$: Observable<boolean>;
events$: Observable<MyEvent>;
foo(): boolean
}
export class HttpBackendService {
connected$ = ...;
events$ = ...;
foo(): boolean { return true; }
constructor(http: HttpService) { ... }
}
export class WebsocketBackendService {
connected$ = ...;
events$ = ...;
foo(): boolean { return false; }
constructor(websocket: WsService) { ... }
}