Angular 2 DI: передать привязку ввода в deps фабричного провайдера
Есть ли простой способ ввести входную привязку в массив deps фабрики провайдеров? Ниже явно не работает.
const myServiceFactory = (object: any) => {
//...
};
@Component({
// ...
inputs: ['object'],
providers: [
{
provide: Object,
useValue: object,
},
{
provide: MyService,
useFactory: myServiceFactory,
deps: [Object]
}
]
})
1 ответ
В качестве возможного решения вы можете попробовать сделать это примерно так:
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);
}
}
Принятый ответ работает хорошо, но если у вас есть несколько зависимостей, "предоставленных" вашим компонентом, которые зависят друг от друга, все становится намного сложнее.
Другой подход, который может сработать, если вы уже активно используете наблюдаемые, - это предоставить LAZY_ID
токен, который на самом деле ReplaySubject<number>
(или любого другого типа, который вам нужен).
В вашем ngOnInit()
ты просто звонишь this.lazyID.next(this.id)
обновить ReplaySubject
со значением, переданным через @Input
.
Кроме того, вы могли бы использовать это 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 ]
},