The accepted answer works well, but if you have several dependencies 'provided' by your component that depend on each other than things get a lot more complicated.
Another approach that may work if you're already heavily using observables is to provide a LAZY_ID
token which is actually a ReplaySubject<number>
(or whatever type you need it to be).
In your ngOnInit()
you simply call this.lazyID.next(this.id)
to update the ReplaySubject
with the value passed in via @Input
.
In addition you would then use this LAZY_ID
with a provider factory to create whatever the primary dependency was.
Disclaimer: I don't think this is a good general solution to this issue. It can get clumsy but sometimes it may work!
Here's a simplified example - would welcome improvements:
export const LAZY_ID = new InjectionToken<ReplaySubject<number>>('LAZY_ID');
export const LazyIDFactory = () =>
{
return new ReplaySubject<number>(1);
}
export const productDataFromLazyIDFactory = (productService: ProductService, id$: ReplaySubject<number>) =>
{
// Create your 'ProductData' from your service and id$
// So yes - the catch here is your ProductData needs to take an observable
// as an input - which only really works if you're extensively using observables
// everywhere. You can't 'wait' for the result here since the factory must return
// immediately
}
Then in your @Component
providers: [
// creates our ReplaySubject to hold the ID
{
provide: LAZY_ID,
useFactory: LazyIDFactory
},
{
provide: ProductData,
useFactory: productDataFromLazyIDFactory,
deps: [ ProductService, LAZY_ID ]
},
ngOnInit() { this.myService.setParam(this.myInput); }
– Estipulate