Angular 2 динамическая зависимость, основанная на @Input()
Предположим, что у меня есть компонентная директива Angular 2, где я хочу, чтобы вложенная зависимость, которую компонент использует, определяется с помощью @Input().
Я хочу написать что-то вроде <trendy-directive use="'serviceA'">
и использовать этот экземпляр TrendyDirective для использования serviceA, или использовать его serviceB, если это то, что я указываю. (это упрощенная версия того, что я на самом деле пытаюсь сделать)
(Если вы считаете, что это ужасная идея для начала, я открыт для этой обратной связи, но, пожалуйста, объясните, почему.)
Вот один пример того, как достичь того, о чем я думаю. В этом примере представьте, что ServiceA и ServiceB - это инъекции, которые реализуют iService с помощью функции superCoolFunction.
@Component({
selector: 'trendy-directive',
...
})
export class TrendyDirective implements OnInit {
constructor(
private serviceA: ServiceA,
private serviceB: ServiceB){}
private service: iService;
@Input() use: string;
ngOnInit() {
switch (this.use){
case: 'serviceA': this.service = this.serviceA; break;
case: 'serviceB': this.service = this.serviceB; break;
default: throw "There no such thing as a " + this.use + '!';
}
this.service.superCoolFunction();
}
}
Я думаю, что это технически будет работать, но должен быть лучший способ сделать динамическую инъекцию зависимостей.
Ответы
Ответ 1
Это
// can be a service also for overriding and testing
export const trendyServiceMap = {
serviceA: ServiceA,
serviceB: ServiceB
}
constructor(private injector: Injector) {}
...
ngOnInit() {
if (trendyServiceMap.hasOwnProperty(this.use)) {
this.service = this.injector.get<any>(trendyServiceMap[this.use]);
} else {
throw new Error(`There no such thing as '${this.use}'`);
}
}
Ответ 2
В общем, такой же подход описан в документации Angular2: InjectorComponent
@Component({
providers: [Car, Engine, Tires, heroServiceProvider, Logger]
})
export class InjectorComponent {
car: Car = this.injector.get(Car);
heroService: HeroService = this.injector.get(HeroService);
hero: Hero = this.heroService.getHeroes()[0];
constructor(private injector: Injector) { }
}
Вы должны ввести Injector
в конструктор и перечислить все службы в providers
свойства аннотации @Component
. Затем вы можете injector.get(type)
, где type
будет разрешено с вашего @Input
. Согласно документации, Service
на самом деле не вводится, пока вы не попросите его (.get()
).
Ответ 3
Существует служба с именем Inject в модуле @ angular/core. С помощью @Inject вы можете добиться альтернативного способа инъекции. Но это можно сделать только в конструкторе.
Итак, вам нужно будет поместить компонентные входы в массив ввода вашего декоратора @component (не использовать встроенный декоратор @Input внутри класса), а затем вставить эту конструкцию в конструктор.