Is there an easy way to inject an input binding into the deps array of a provider factory? Below obviously does not work.
const myServiceFactory = (object: any) => {
//...
};
@Component({
// ...
inputs: ['object'],
providers: [
{
provide: Object,
useValue: object,
},
{
provide: MyService,
useFactory: myServiceFactory,
deps: [Object]
}
]
})
As a possible solution you can try to do it something like this:
const myServiceFactory = (self: Child) => {
return new MyService(self.param);
};
class MyService {
constructor(private param: string) {}
}
@Component({
selector: 'child',
template: `{{ param }}`,
providers: [
{
provide: MyService,
useFactory: myServiceFactory,
deps: [Child]
}
]
})
export class Child {
@Input() param: any;
constructor(private inj: Injector) { }
ngOnInit() { // or ngOnChanges
let service = this.inj.get(MyService);
}
}
Plunker Example
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 ]
},
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With