使用 AOT 的类型提供程序中的角度条件

Posted

技术标签:

【中文标题】使用 AOT 的类型提供程序中的角度条件【英文标题】:Angular condition in type provider with AOT 【发布时间】:2018-08-01 04:49:16 【问题描述】:

我有一个使用 AOT 编译的 Angular 项目。我希望能够注册根据配置动态解析的ClassProvider。我使用的简化代码是这样的:

const isMock = Math.random() > 0.5;

@NgModule(
  // ...
  providers: [
     provide: MyServiceBase, useClass: (isMock) ? MyServiceMock : MyService ,
  ],
  bootstrap: [AppComponent]
)
export class AppModule  

问题是当我用 AOT 编译它时,我总是得到相同的服务。我希望在按 F5 时获得不同的服务(因为第一行的randomness)。在没有 AOT 的情况下编译时,它的行为符合我的预期。

这是 github 上的完整代码示例:https://github.com/vdolek/angular-test/tree/aot-conditioned-provider-problem。它与 ng serveng serve --aot 的行为不同。

我怎样才能做到这一点?我知道我可以使用FactoryProvider,但是我必须复制服务依赖项(FactoryProvider 上的工厂函数和 deps 属性的参数)。

【问题讨论】:

【参考方案1】:

要实现您需求的动态特性,您需要通过useFactory 属性使用factory providers,。

我已经分叉了您的存储库,并修改了您的 app.module.ts 如下,以便在 AOT 中工作。

修改app.module.ts如下

export let myServiceFactory = () => 

  const isMock = Math.random() > 0.5;

  return isMock ? new MyServiceMock() : new MyService();
; 

@NgModule(
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [
    provide: MyServiceBase, useFactory: myServiceFactory,
  ],
  bootstrap: [AppComponent]
)
export class AppModule 

如果您的服务依赖于其他服务(很可能会),您可以使用 deps 参数传递所需的依赖关系。

假设MyServiceBase 依赖于两个服务,MyService1MyService2...您的工厂函数将如下所示:

export let myServiceFactory = (service1:MyService1, service2:MyService2) => 

  const isMock = Math.random() > 0.5;

  return isMock ? new MyServiceMock(service1, service2) : new MyService(service1, service2);
; 

您的提供者声明如下所示

providers: [
    
       provide: MyServiceBase, 
       useFactory: myServiceFactory,
       deps: [MyService1, MyService2]
    ,
]

This guide 包含有关在 Angular 中实现依赖注入的各种方法的更多详细信息。

【讨论】:

感谢您的回答。正如我在问题中提到的,我熟悉 FactoryProviders。但我不喜欢我需要列出三次依赖项(在实际服务中、在工厂签名中和在deps 属性中)。我想避免这种代码重复——这就是问题的目的。 deps 属性甚至不会在构建时进行静态检查,因此当有人更改服务的依赖项时,他必须知道更改 deps 属性。 我明白,我不得不承认,我错过了最后一句话(我的脑海里自动想到了那个解决方案)。据我所知,没有其他方法可以满足您的要求。 Angular 5 在使用 AOT 时减少了对工厂函数等语法的限制。【参考方案2】:

我认为正如@jeanpaul-a 所说,除了使用工厂之外,您别无选择。但是管理依赖关系可能不是很干净。但是您可以使用Injector。我会选择类似的东西:

@NgModule(
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, HelloComponent ],
  providers: [
    Dep1Service,
    Dep2Service,
     provide: MyServiceBase, useFactory: createService, deps: [Injector] 
  ],
  bootstrap:    [ AppComponent ]
)
export class AppModule  

export function createService(injector: Injector) 
  const isMock = Math.random() > 0.5;
  if (mock) 
    return new MyService1(injector.get(Dep2Service));
   else 
    return new MyService2(injector.get(Dep1Service));
  

您还可以将 MyServiceBase 设置为接口并使用InjectionToken。 您将找到一个工作示例 here(但不是您的班级名称)。

【讨论】:

感谢您的回答。这不是我 100% 的愿望。但至少每次依赖项发生变化时都会出现构建错误,因此人们知道需要更新工厂。 是的,我知道,但是你不能在 useClass 中使用函数调用,并且当使用 AOT 编译时,你的表达式将是静态的。所以如果你想要一些动态,你需要一个工厂

以上是关于使用 AOT 的类型提供程序中的角度条件的主要内容,如果未能解决你的问题,请参考以下文章

同一项目上的角度 AOT 和 JIT

在角度通用应用程序(nodejs)上集成newrelic

条件角度组件提供者

角度构建大小与sass是巨大的

tslint 不排除角度项目中的 node_modules

如何根据使用角度 7 中的键的条件检查来过滤 json 响应中的数组