Angular 2 DI:将输入绑定传递给工厂提供者的部门
Angular 2 DI: pass input binding to deps of factory provider
有没有一种简单的方法可以将输入绑定注入提供程序工厂的 deps 数组?下面显然不行。
const myServiceFactory = (object: any) => {
//...
};
@Component({
// ...
inputs: ['object'],
providers: [
{
provide: Object,
useValue: object,
},
{
provide: MyService,
useFactory: myServiceFactory,
deps: [Object]
}
]
})
作为一种可能的解决方案,您可以尝试这样做:
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);
}
}
接受的答案很好,但是如果你的组件有多个依赖项 'provided' 并且相互依赖,那么事情就会变得复杂得多。
如果您已经大量使用可观察对象,另一种可能有效的方法是提供一个 LAZY_ID
令牌,它实际上是一个 ReplaySubject<number>
(或您需要的任何类型)。
在您的 ngOnInit()
中,您只需调用 this.lazyID.next(this.id)
即可使用通过 @Input
.
传入的值更新 ReplaySubject
此外,您可以将此 LAZY_ID
与提供者工厂一起使用来创建主要依赖项。
免责声明:我认为这不是解决此问题的通用解决方案。它可能会变得笨拙,但有时它可能会起作用!
这是一个简化的示例 - 欢迎改进:
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
}
然后在你的@Component
providers: [
// creates our ReplaySubject to hold the ID
{
provide: LAZY_ID,
useFactory: LazyIDFactory
},
{
provide: ProductData,
useFactory: productDataFromLazyIDFactory,
deps: [ ProductService, LAZY_ID ]
},
有没有一种简单的方法可以将输入绑定注入提供程序工厂的 deps 数组?下面显然不行。
const myServiceFactory = (object: any) => {
//...
};
@Component({
// ...
inputs: ['object'],
providers: [
{
provide: Object,
useValue: object,
},
{
provide: MyService,
useFactory: myServiceFactory,
deps: [Object]
}
]
})
作为一种可能的解决方案,您可以尝试这样做:
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);
}
}
接受的答案很好,但是如果你的组件有多个依赖项 'provided' 并且相互依赖,那么事情就会变得复杂得多。
如果您已经大量使用可观察对象,另一种可能有效的方法是提供一个 LAZY_ID
令牌,它实际上是一个 ReplaySubject<number>
(或您需要的任何类型)。
在您的 ngOnInit()
中,您只需调用 this.lazyID.next(this.id)
即可使用通过 @Input
.
ReplaySubject
此外,您可以将此 LAZY_ID
与提供者工厂一起使用来创建主要依赖项。
免责声明:我认为这不是解决此问题的通用解决方案。它可能会变得笨拙,但有时它可能会起作用!
这是一个简化的示例 - 欢迎改进:
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
}
然后在你的@Component
providers: [
// creates our ReplaySubject to hold the ID
{
provide: LAZY_ID,
useFactory: LazyIDFactory
},
{
provide: ProductData,
useFactory: productDataFromLazyIDFactory,
deps: [ ProductService, LAZY_ID ]
},