typescript 基于@Input() 的Angular 2 动态依赖注入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41366108/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:07:37  来源:igfitidea点击:

Angular 2 dynamic dependency injection based on @Input()

angulartypescriptdependency-injection

提问by John

Suppose I have an Angular 2 component-directive, where I want the injected dependency that the component uses to be determined by an @Input().

假设我有一个 Angular 2 组件指令,我希望组件使用的注入依赖项由 @Input() 确定。

I want to write something like <trendy-directive use="'serviceA'">and have that instance of TrendyDirective use serviceA, or have it use serviceB if that's what I specify. (this is an oversimplified version of what I'm actually trying to do)

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

(If you think this is a terrible idea to begin with, I'm open to that feedback, but please explain why.)

(如果您认为这是一个糟糕的主意,我愿意接受该反馈,但请解释原因。)

Here's one example of how to achieve what I'm thinking of. In this example, imagine that ServiceA and ServiceB are injectables that both implement iService by having a 'superCoolFunction'.

这是如何实现我所想的一个例子。在这个例子中,假设 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();
    }
}

I think this technically would work, but there's got to be a better way to do dynamic dependency injection.

我认为这在技术上可行,但必须有更好的方法来进行动态依赖注入。

回答by Estus Flask

It is

它是

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

回答by A. Tim

In general, same approach is described in Angular2 documentation: InjectorComponent

一般来说,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) { }
}

You must inject Injectorin constructor and list all services in providersproperty of @Componentannotation. Then you can injector.get(type), where typewill be resolved from your @Input. As per documentation, Serviceis not actually injected until you ask for it (.get()).

您必须注入Injector构造函数并在注释providers属性中列出所有服务@Component。然后你就可以了injector.get(type),哪里type会从你的@Input. 根据文档,Service在您要求之前不会实际注入 ( .get())。

回答by Vineet 'DEVIN' Dev

There is a service named Inject in @angular/core module. With @Inject you can achieve alternative way of injection. But that can be done only in constructor.

@angular/core 模块中有一个名为 Inject 的服务。使用@Inject,您可以实现替代注入方式。但这只能在构造函数中完成。

So you will need to put component's inputs in the inputs array of your @component decorator (do not use @Input decorator inside class) and then inject that input variable in constructor.

因此,您需要将组件的输入放入 @component 装饰器的输入数组中(不要在类中使用 @Input 装饰器),然后在构造函数中注入该输入变量。