web-dev-qa-db-fra.com

Injection de dépendance dynamique angulaire 2 basée sur @Input ()

Supposons que je dispose d'une directive de composant angulaire à deux composants, dans laquelle je souhaite que la dépendance injectée utilisée par le composant soit déterminée par un @Input ().

Je veux écrire quelque chose comme <trendy-directive use="'serviceA'"> et que cette instance de TrendyDirective utilise serviceA, ou utilise serviceB si c'est ce que je spécifie. (ceci est une version simplifiée à l'extrême de ce que j'essaie de faire)

(Si vous pensez que c'est une idée terrible pour commencer, je suis ouvert à ce retour, mais expliquez pourquoi.)

Voici un exemple de réalisation de ce à quoi je pense. Dans cet exemple, imaginons que ServiceA et ServiceB sont des injectables qui implémentent tous les deux iService en ayant un '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's no such thing as a " + this.use + '!';
        }
        this.service.superCoolFunction();
    }
}

Je pense que cela fonctionnerait techniquement, mais il doit y avoir une meilleure façon de faire une injection dynamique de dépendance.

16
John

Il est

// 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's no such thing as '${this.use}'`);
    }
}
10
estus

En général, la même approche est décrite dans la documentation 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) { }
}

Vous devez injecter Injector dans le constructeur et répertorier tous les services dans la propriété providers de l'annotation @Component. Ensuite, vous pouvez injector.get(type), où type sera résolu à partir de votre @Input. Conformément à la documentation, Service n’est réellement injecté que lorsque vous le demandez (.get()).

4
A. Tim

Il existe un service nommé Inject in @ angular/core module. Avec @Inject, vous pouvez réaliser un autre mode d'injection. Mais cela ne peut être fait que dans le constructeur. 

Vous devrez donc placer les entrées de composant dans le tableau d'entrées de votre décorateur @component (n'utilisez pas de décorateur @Input dans la classe), puis injecter cette variable d'entrée dans le constructeur.

2
Vineet 'DEVIN' Dev