【问题标题】:Angular 2 Set APP_BASE_HREF with a value from a Promise / ObservableAngular 2 使用来自 Promise / Observable 的值设置 APP_BASE_HREF
【发布时间】:2018-02-21 17:40:36
【问题描述】:

我尝试使用来自异步休息调用的值设置“CoreModule”中的 APP_BASE_HREF。 我看不出这是怎么做到的,因为提供方法需要返回一个字符串。

例如:

@NgModule({
    imports: [
        ...
        HttpModule
    ],
    ...
    providers: [
        ...
        ...
        BackendRequestClass,
        { provide: APP_BASE_HREF, useFactory: () => () => return '/some/path', deps: [], multi: true }
    ],
});

但是当我需要来自 web 服务的值时,我无法返回字符串。 有什么想法可以做到吗?

谢谢

【问题讨论】:

    标签: javascript angular aot


    【解决方案1】:

    我尝试了您的解决方案。 问题是,当时

    { provide: APP_BASE_HREF, useFactory: (config) => config.appBaseHref, deps: [ConfigService] }
    

    config.appBaseHref 尚未设置。 当我调试我看到的代码时,APP_INITIALIZER 在来自APP_BASE_HREF 的提供程序之后执行

    这导致 BASE_HREF 未设置。

    【讨论】:

      【解决方案2】:

      我们遇到了同样的挑战:根据异步 API 调用的结果动态设置 APP_BASE_HREF,以允许路由可通过不同 URL 访问的应用程序。

      虽然 Günter 提供的 solution 看起来不错,但不幸的是它不起作用,至少在 Angular 7 中是这样。在我们的例子中,APP_BASE_HREF 总是优先于 APP_INITIALIZER,所以我们无法初始化 @987654325 @ 基于从初始化程序返回的已解析的承诺值。

      相反,我实现了在 Angular 引导之前发生的 API 调用,然后注入提供程序,以便它在 Angular 上下文中可用。

      添加到main.ts:

      fetchConfig().then(config => {
        platformBrowserDynamic([ { provide: ConfigData, useValue: config } ])
          .bootstrapModule(AppModule)
          .catch(err => console.log(err));
      });
      

      然后我们可以在providers中配置APP_BASE_HREFapp.module.ts:

      providers: [
        // …
        { 
          provide: APP_BASE_HREF, 
          useFactory: (config: ConfigData) => config.base, 
          deps: [ ConfigData ] 
        }
      ]
      

      [编辑 2019-08-21] 根据 cmets 的说明:fetchConfig() 是获取配置并返回 Promise 的 API 请求。 ConfigData 不是 Angular 服务,而只是一个简单的类,它在 fetchConfig() 中被实例化,并且在稍后在我的应用程序中访问它时为我提供了类型安全性:

      function fetchConfig (): Promise<ConfigData> {
        return fetch('/api/config')
          .then(response => response.json())
          .then(response => new ConfigData(response));
      }
      

      【讨论】:

      • 与其去“外部”Angular,不如使用 PLATFORM_INITIALIZER 机制来获取配置。这很好而且很早就开始了(肯定是在 APP_INITIALIZER 之前)。 platformBrowserDynamic([{ provide: PLATFORM_INITIALIZER, useValue: fetchConfig, multi: true }]).bootstrapModule(AppModule)
      • @GaryMcGill 感谢您的意见——我会在有空的时候试一试!
      • @qqilihq 我可以看到 fetchConfig() 的代码吗?你在哪里定义 main.ts 中的配置?
      • @Arnold.Krumins 这只是一个获取配置并解析为承诺的 HTTP 请求。
      • @qqilihq 好的,谢谢。 ConfigData 是一项服务吗?如果是这样,您是如何在 main.ts 中创建它的?
      【解决方案3】:

      可以使用APP_INITIALIZER提前获取路径,然后使用Angularjs2 - preload server configuration before the application starts所示的依赖项

      export function loadConfig(config: ConfigService) => () => config.load()
      
      @NgModule({
          declarations: [AppComponent],
          imports: [BrowserModule,
              routes,
              FormsModule,
              HttpModule],
          providers: [
              ConfigService,
              BackendRequestClass,
              { provide: APP_INITIALIZER,
                useFactory: loadConfig,
                deps: [ConfigService], 
                multi: true },
              { provide: APP_BASE_HREF, useFactory: (config) => config.appBaseHref, deps: [ConfigService] }
      
          ],
          bootstrap: [AppComponent]
      })
      export class AppModule { }
      

      ConfigService 可以注入 BackendRequestClassHttp 并获取数据,然后使用其 appBaseHref 属性使其可用(只是一个示例)。

      【讨论】:

      • 这在理论上看起来是一个很好的解决方案,但是,APP_BASE_HREF 似乎在 before APP_INITIALIZER 之前被执行(至少在较新的 Angular 版本上——我正在使用7)。这是否发生了变化,还是我缺少什么?
      • 我已经有一段时间没有使用 Angular 了,也不知道。
      猜你喜欢
      • 1970-01-01
      • 2023-04-09
      • 2017-08-03
      • 1970-01-01
      • 2016-08-15
      • 2018-08-23
      • 2017-10-12
      • 1970-01-01
      相关资源
      最近更新 更多