【问题标题】:How to add providers to Injector dynamically?如何动态地将提供程序添加到 Injector?
【发布时间】:2021-03-27 07:15:20
【问题描述】:

每个组件都可以使用ComponentMetadata 中的providers 属性指定新的Providers。

有没有办法从组件的constructor 动态指定提供者?

【问题讨论】:

    标签: javascript angular angular2-di


    【解决方案1】:

    我使用 useFactory 来确定将用于提供的类。 我为谁担心。

    在组件 ts 中

    @Component({
        selector: 'app-chart',
        templateUrl: './chart.component.html',
        styleUrls: ['./chart.component.scss'],
        providers: [
            { provide: DateTimeAdapter, useClass: MomentDateTimeAdapter },
            { provide: OWL_DATE_TIME_FORMATS, useValue: CUSTOM_FORMATS },
            { provide: OwlDateTimeIntl, deps: [SettingService],
                useFactory: (settingsService) => settingsService.getLanguage()
            }
        ]
    })
    

    在服务中 ts 获取类实例

    @Injectable()
    export class SettingService {
        public getLanguage(){
           return this.translate.currentLang == "ko" ? new KoreanIntl() : new DefaultIntl;
        }
    }
    

    【讨论】:

    • 是否可以根据您使用的 settingService.getLanguage() 条件动态注入 useValue
    【解决方案2】:

    以下是实施动态提供程序需要遵循的 3 个更广泛的步骤。请注意,我已经评论了代码的许多部分,以便我们专注于主要答案。如果您想查看详细步骤,请参阅此Angular tutorial

    第 1 步:- 创建提供者的集合

    创建集合,可以使用push方法动态添加DI对象。

    var providerscoll:any = [];
    providerscoll.push({ provide: "1", useClass: DialogLogger });
    providerscoll.push({ provide: "2", useClass: ConsoleLogger });
    

    第 2 步:- 在“NgModule”中提供提供者集合。

    请参阅方括号语法。

    @NgModule({
        // code removed for clarity
        providers: [providerscoll]
    })
    export class MainModuleLibrary { }
    

    第 3 步:- 在构造函数中获取 Injector 对象

    使用 DI 在构造函数中获取注入器对象,然后您可以使用“Get”方法和令牌进行查找。因此,如果你提供“1”,那么你会得到一些东西,如果你提供“2”,你就会得到一些东西。

    // code removed for clarity
    import {  Injector } from '@angular/core';
    // code removed for clarity
    export class CustomerComponent {
    constructor(public injector: Injector){
            this.logger = this.injector.get("2");
        }
    }
    

    【讨论】:

    • 这不是动态提供者,这只是使用 Injector 延迟注入。
    • 你的意思是你想在某些事件点击或其他地方从组件内部更改注入器。
    • 是的,假设您有一个用户输入,并且您想使用该输入来设置提供程序,以便稍后实例化的组件可以使用它。
    • 所有解析的依赖都在 mainModule 的范围内。 OP 要求在组件级别添加依赖项。
    【解决方案3】:

    我已经在引导部分完成了。

    bootstrap(AppComponent,[
        provide( RequestOptions, { useClass: DefaultRequestOptions } ),
        provide(Http, { useFactory:
            function(backend, defaultOptions) {
                return new Http(backend, defaultOptions); },
            deps: [XHRBackend, RequestOptions]}),
    ]);
    

    我猜它也可以在组件中完成:

    https://angular.io/docs/ts/latest/api/http/Http-class.html

    您可以通过将决策添加到工厂函数中来使其动态化,而不仅仅是返回相同的对象。

    【讨论】:

    • 现在 2.0.0 发布了,这似乎不起作用。我一直在反对它试图让它发挥作用。
    【解决方案4】:

    有一种方法可以使用ViewContainerRef 创建组件,其中允许传递injector,所以我想这应该是可能的,但仅限于动态创建组件:

    创建注入器:

    static create(options: {providers: StaticProvider[], parent?: Injector, name?: string}): Injector;
    
    // @param injector The injector to use as the parent for the new component.
    
    abstract createComponent<C>(
        componentFactory: ComponentFactory<C>, index?: number, injector?: Injector,
        projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>;
    

    伪代码:

    class FooComponent {
    
      constructor(
        private readonly injector: Injector,
        private readonly viewContainer: ViewContainerRef){
        const customInjector = this.injector.create({ providers: [FooService], parent: injector });
        this.viewContainer.createComponent(componentFactory, 0, customInjector );
        ...
      }
    }
    

    或者类似地使用来自Angular CDK的Portal。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-28
      • 1970-01-01
      • 2014-04-05
      • 1970-01-01
      • 1970-01-01
      • 2019-07-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多