Angular模块如何引入其他模块并通过forRoot传递自定义参数实例化
结论
你不能直接在@NgModule的imports配置中取用已注册的MyServiceProvider实例传递给依赖模块。原因是@NgModule的元数据属于静态编译期配置,会在Angular编译模块时提前解析,而你在forRoot方法中注册的Provider属于运行期依赖注入项,二者执行时序完全不匹配,无法直接互通。
实现方案
你可以直接在自定义模块的forRoot静态方法内部处理第三方模块的配置,利用闭包特性直接拿到用户传入的配置参数,完全不需要修改第三方模块的代码,适配你封装ngx-translate的场景写法如下:
import { NgModule, ModuleWithProviders } from '@angular/core'; import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { HttpClient } from '@angular/common/http'; // 自定义服务Provider(你原来的业务Provider) export class MyServiceProvider { constructor(public config: {custom: string[]}) {} } @NgModule({ // 这里仅引入不需要动态传参的静态依赖模块 imports: [], // 导出TranslateModule供外层业务模块直接使用翻译能力 exports: [TranslateModule] }) export class MyServiceModule { static forRoot(config: {custom: string[]}): ModuleWithProviders<MyServiceModule> { // 闭包直接捕获用户传入的config参数,不需要额外通过依赖注入传递 const customLoaderFactory = (http: HttpClient) => { // 直接用拿到的custom参数构造loader,比如拼接翻译资源路径 return new TranslateHttpLoader(http, config.custom[0], '.json'); }; return { ngModule: MyServiceModule, // 第三方模块的forRoot调用直接放在这里,动态传入配置 imports: [ TranslateModule.forRoot({ loader: { provide: TranslateLoader, useFactory: customLoaderFactory, deps: [HttpClient] } }) ], providers: [ // 你原有需要注册的自定义Provider { provide: MyServiceProvider, useValue: config } ] }; } }
方案说明
- Angular从7版本开始支持
ModuleWithProviders返回值中携带imports配置,你可以把需要动态传参的依赖模块调用全部移到forRoot方法的返回值中,直接使用方法入参的配置完成初始化。 - 利用闭包特性可以直接在
forRoot内部访问到用户传入的配置,不需要额外通过依赖注入的Token来传递参数,代码更简洁。
内容的提问来源于stack exchange,提问作者Raphaël Balet
相关产品推荐
相关产品推荐

