2016-12-28 56 views
10

假设我有一个Angular 2组件指令,其中我希望组件使用的注入依赖由@Input()确定。基于@Input的角度2动态依赖注入()

我想写一些类似<trendy-directive use="'serviceA'">的东西,并让TrendyDirective的实例使用serviceA,或者让它使用serviceB(如果这是我指定的)。 (这是什么实际上,我试图做一个过于简化版本)

(如果你认为这是一开始就有一个可怕的想法,我接受这些反馈,但请解释原因。)

下面是如何实现我所想的一个例子。在这个例子中,假设ServiceA和ServiceB是通过具有'superCoolFunction'来实现iService的注入。

@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(); 
    } 
} 

我认为这在技术上是可行的,但是有一个更好的方法来做动态依赖注入。

回答

4

它是

// 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}'`); 
    } 
} 
+0

由于4.0'get'已被弃用。 –

+0

我的意思是签名。请参阅https://github.com/angular/angular/blob/5.2.5/packages/core/src/di/injector.ts#L62 –

+0

使用类型调用泛型方法总是更好。我不确定这个签名是否会被删除。它可以让用户知道使用泛型更好。无论如何,我更新了答案,感谢您的关注。通常我不打扰彻底输入解决方案,并专注于提供它的要点。 – estus

2

有一个@角/芯模块在名为进样的服务。使用@Inject您可以实现替代注射方式。但是这只能在构造函数中完成。

所以你需要将组件的输入放入你的@component装饰器的输入数组(不要在类里面使用@Input装饰器),然后在构造函数中注入输入变量。

+1

我也会为注射投票: 您是否会在其父组件中多次使用trendy-directive或将其切换为动态?如果没有,父组件可以简单地提供正确的服务,而且不需要实现复杂的逻辑。 '''@Component({selector:'i-use-trendy-directive',providers:[{provide:MyServiceInterfase,useClass:MyServiceImpl}]}'''然后'''构造函数(private myService:MyServiceInterface){} '' –

+0

在我的情况下,我会在不止一个地方使用不同服务的指令,谢谢 – John

+0

@Vineet'DEVIN'Dev这非常有趣,装饰器中输入数组的文档看起来很稀疏。在'@ Component'装饰器中的元素在组件生命周期中的地址比'@ Input'装饰器中指定的更早。 – John

3

一般来说,同样的方法也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@Component注释providers属性列表中的所有服务。那么你可以injector.get(type),其中type将从您的@Input解决。根据文件,Service实际上并没有注入,直到你要求它(.get())。