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 внутри класса), а затем вставить эту конструкцию в конструктор.