微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在 Angular 应用程序启动之前获取提供者数据

如何解决如何在 Angular 应用程序启动之前获取提供者数据

我的目标是从 AppConfigService 异步获取“clientId”,并在应用启动之前将其用作“GoogleLoginProvider”函数的“clientId”。

我可以把它放在一个环境变量中,但在我的特定情况下,它不是一个选项。

我使用的是 Angular 8。

import { APP_INITIALIZER } from '@angular/core';

export function getGoogleClientId(appConfigService: AppConfigService) {
    return () => appConfigService.getGoogleClientId().toPromise().then((clientId) => {
        // service reliably returns clientId here
    });
}

const getGoogleId: Provider = {
    provide: APP_INITIALIZER,useFactory: getGoogleClientId,deps: [AppConfigService],multi: true
}

@NgModule({
    providers: [
        {
            provide: 'SocialAuthServiceConfig',useValue: {
                autoLogin: false,providers: [{
                    id: GoogleLoginProvider.PROVIDER_ID,provider: new GoogleLoginProvider(clientId),//<-- How do I get the service's "clientId" here?
                }],} as SocialAuthServiceConfig
        }
    ]
})
export class AppModule {}

解决方法

您的问题是您使用 useValue 注入对象,但您需要使用 useFactory 根据运行时之前不可用的信息创建可更改的依赖值,从而允许依赖(API 服务、配置服务等)。

那么我建议修改您此时使用的库 (angularx-social-login) 以允许您想要的行为。

然而,我正在阅读库代码,我意识到他们接受一个对象和一个承诺!

You can check It here

因此,我创建了一个示例来处理 promise 并从我们的服务器 (API) 中获取我们的配置。

app.module.ts

export function AppConfigServiceFactory(
  configService: AppConfigService
): () => void {
  return async () => await configService.load();
}

@NgModule({
  imports: [BrowserModule,FormsModule,SocialLoginModule,HttpClientModule],declarations: [AppComponent,HelloComponent],bootstrap: [AppComponent],providers: [
    {
      provide: APP_INITIALIZER,useFactory: AppConfigServiceFactory,deps: [AppConfigService],multi: true
    },{
      provide: "SocialAuthServiceConfig",useValue: new Promise(async resolve => {
        // await until the app config service is loaded
        const config = await AppConfigService.configFetched();

        resolve({
          autoLogin: false,providers: [
            {
              id: GoogleLoginProvider.PROVIDER_ID,provider: new GoogleLoginProvider(config.googleClientId)
            }
          ]
        } as SocialAuthServiceConfig);
      })
    }
  ]
})
export class AppModule {}


app.config.service

export class AppConfigService {
  static config: AppConfig | null = null;

  constructor(private api: ApiService) {}

  static configFetched(): Promise<AppConfig> {
    return new Promise(async resolve => {
      // wait for the app config service is loaded (after 3000 ms)
      const sleep = (ms: number) => new Promise(r => setTimeout(r,ms));
      const waitFor = async function waitFor(f) {
        // check each 500 ms
        while (!f()) await sleep(500);
        return f();
      };
      await waitFor(() => AppConfigService?.config); 

      resolve(AppConfigService.config);
    });
  }

  async load(): Promise<AppConfig> {
    try {
      // simulating HTTP request to obtain my config
      const promise = new Promise<AppConfig>(resolve => {

        // after 3000 ms our config will be available
        setTimeout(async () => {
          const config: AppConfig = await this.api.getConfig().toPromise();
          AppConfigService.config = config;
          resolve(config);
        },3000);

      }).then(config => config);

      return promise;
    } catch (error) {
      throw error;
    }
  }
}

My complete solution is here on stackblitz.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。