How to write a service that requires constructor parameters?
You can make the parameters optional by adding @Optional()
(DI) and ?
(TypeScript), and @Inject(somekey)
for primitive values that are not supported as provider keys
@Injectable()export class MetricsService { constructor( private http: Http, @Inject('wsAuthKey') @Optional() public wsAuthKey?: string, @Inject('wsHost') @Optional() public wsHost?: string ) { this.wsAuthKey = wsAuthKey || "blahblahblahblahblahblahblahblah="; this.wsHost = wsHost || "https://preprod-admin.myservice.ws"; }
providers: [ {provide: 'wsAuthKey', useValue: 'abc'}, {provide: 'wsHost', useValue: 'efg'}, ]
If they are provided, they are passed, otherwise they are ignored, but DI still can inject the MetricsService
.
This is a common recipe that is described in this question in particular. It should be a service that holds the configuration:
@Injectable()export class MetricsConfig { wsAuthKey = "blahblahblahblahblahblahblahblah="; wsHost = "https://preprod-admin.myservice.ws";}@Injectable()export class MetricsService { constructor( private http: Http, metricsConfig: MetricsConfig ) { this.wsAuthKey = metricsConfig.wsAuthKey; this.wsHost = metricsConfig.wsHost; }}
In the case when it needs to changed, it can be overridden or extended for entire module or for particular component:
@Component( ... { provide: MetricsConfig, useClass: class ExtendedMetricsConfig { ... } })export class DatavizComponent ...
There's no real need to make MetricsConfig
a class in this case. It can be an OpaqueToken value provider as well. But a class can be conveniently extended, it is easier to inject and already provides an interface for typing.
From the official docs: https://angular.io/guide/dependency-injection-in-action#injectiontoken
Use an @Optional
decorator in the constructor:
export class MyService { constructor( @Optional() public var: type = value ) { }}