在APP_INITIALIZER完成之前初始化Angular 5服务

jus*_*web 8 angular angular5

我正在将AngularJS 1.6应用程序转换为Angular 5,我试图弄清楚为什么我的服务在APP_INITIALIZER完成之前被初始化.

语境:

  • 我需要在初始化应用程序之前使用httpClient获取应用程序配置
  • 所有http请求都需要从获取的配置中获取应用ID才能解析

在AngularJS 1.6中:

在这里,我做了一个HTTP请求来获取应用程序配置,并且我存储在一个.value()所以我可以在引导它之后将其注入我的所有应用程序中.

function getApp(): ng.IHttpPromise<Application> {
  const injector = angular.injector(['ng']);
  const $http: ng.IHttpService = injector.get('$http');
  const appSlug: string = window.location.pathname.split('/')[1];

  return $http.get(`/v3/app/${appSlug}`, { headers: { 'Cache-Control': 'no-cache' } });
}

getApp()
  .then((application) => {
    angular.module(app)
      .value('APP_CONFIG', angular.extend({}, application.data, ENV));

    bootstrap();
  })
  .catch((error) => {
    alert('There was an error starting the app. Please try refreshing your browser.');
  });
Run Code Online (Sandbox Code Playgroud)

在Angular 5中:

目前的行为:

  • 执行news.service.ts类构造函数(这是我需要应用程序ID的地方)
  • APP_INITIALIZER工厂解析(这是我将app id分配给app.provider.ts的地方)
  • news.component.ts ngOnInit按预期调用(在APP_INITIALIZER完成后)

与AngularJS 1.6应用程序实现相同行为的策略是什么?

码:

app.module.ts

export function startupServiceFactory(appProvider: AppProvider): Function {
  return () => appProvider.load();
}

@NgModule({
  declarations: [
    AppComponent,
  ],

  imports: [
    BrowserModule,
    CommonModule,
    HttpClientModule,
    CoreModule,
    ColumnViewModule,

    NavBarModule,
    SideMenuModule,
    NewsModule,

    UIRouterModule.forRoot({ states: STATES }),
  ],

  providers: [
    AppProvider,
    { provide: APP_INITIALIZER, useFactory: startupServiceFactory, deps: [AppProvider], multi: true },
    SideMenuService,
  ],

  bootstrap: [AppComponent]
})
export class AppModule { }
Run Code Online (Sandbox Code Playgroud)

app.provider.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { IApplicationConfig } from './app.interface';

@Injectable()
export class AppProvider {
  public APP_CONFIG: IApplicationConfig;

  constructor(private http: HttpClient) {}

  public getAppConfig() {
    return this.APP_CONFIG;
  }

  public load(): Promise<any> {
    const appSlug: string = window.location.pathname.split('/')[1];

    return new Promise((resolve, reject) => {
      this.http
        .get(`/v3/app/rca-dev-test`)
        .subscribe((response: IApplicationConfig) => {
          this.APP_CONFIG = response;
          resolve(true);
        });
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

Hed*_*ats 0

我就是这样做的:

将您的设置作为 JSON 文件存储在资产文件夹中。

例如:

{
  "apiUrl": "https://localhost:9001/api/v1"
}
Run Code Online (Sandbox Code Playgroud)

启动服务工厂.ts

export const startupServiceFactory = (appProvider: AppProvider) => () =>
  new Promise(async (resolve) => {
    await appProvider.load();
    resolve(true);
  });
Run Code Online (Sandbox Code Playgroud)

appProvider.ts中的相关代码

  public async load(): Promise<any> {
    this.appConfig = await this.http
    .get('assets/appSettings/appSettings.json')
    .pipe(shareReplay(1))
    .toPromise();
  }
Run Code Online (Sandbox Code Playgroud)

确保从 appProvider.ts 中的 rxjs/operators 导入 shareReplay:

import { shareReplay } from 'rxjs/operators';
Run Code Online (Sandbox Code Playgroud)

您的app.module.ts可以保持不变,只需导入startupServiceFactory.