如何使用 Angular 服务动态设置 angular-google-maps api 密钥?

问题描述 投票:0回答:1

我正在使用

@agm/[email protected]
Angular 14.2.10
。 api key是由服务器提供的,所以我创建了一个
EnvService
,它有以下方法

  /**
   * get google map api key
   * @returns Observable<any>
   */
  getMapsKey(): Observable<EnvResponse> {
    return this.getRequest(this.urls.base + '/env/maps-key').pipe(takeUntil(this.ngUnsubscribe));
  }

返回以下 json 响应

{
    "googleMapsApiKey": "apiKey"
}

我遵循了本指南https://gist.github.com/msaxena25/fa59c2130642de3ef6330c6cff2ce6c2,但我无法让它工作。当我在 AppModule 提供程序上设置

{ provide: MapsAPILoader, useClass: CustomLazyAPIKeyLoader}
时,我的 PdoProfileComponent 上出现以下错误:

ERROR NullInjectorError: R3InjectorError(PdoProfileModule)[MapsAPILoader -> MapsAPILoader -> undefined -> undefined -> undefined]: 
  NullInjectorError: No provider for undefined!
    at NullInjector.get (core.mjs:6359:27)
    at R3Injector.get (core.mjs:6786:33)
    at R3Injector.get (core.mjs:6786:33)
    at R3Injector.get (core.mjs:6786:33)
    at injectInjectorOnly (core.mjs:4782:33)
    at Module.ɵɵinject (core.mjs:4786:60)
    at Object.CustomLazyAPIKeyLoader_Factory [as factory] (custom-apikey-loader.service.ts:14:45)
    at R3Injector.hydrate (core.mjs:6887:35)
    at R3Injector.get (core.mjs:6775:33)
    at R3Injector.get (core.mjs:6786:33)

pdo-profile.component.ts:132 ERROR Error: NG0200: Circular dependency in DI detected for MapsAPILoader. Find more at https://angular.io/errors/NG0200
    at throwCyclicDependencyError (core.mjs:240:11)
    at R3Injector.hydrate (core.mjs:6883:13)
    at R3Injector.get (core.mjs:6775:33)
    at R3Injector.get (core.mjs:6786:33)
    at ChainedInjector.get (core.mjs:13769:36)
    at lookupTokenUsingModuleInjector (core.mjs:3293:39)
    at getOrCreateInjectable (core.mjs:3338:12)
    at ɵɵdirectiveInject (core.mjs:10871:12)
    at Module.ɵɵinject (core.mjs:4786:60)
    at NodeInjectorFactory.GoogleMapsAPIWrapper_Factory [as factory] (agm-core.js:222:126)

当我从 AppModule 提供程序中删除

{ provide: MapsAPILoader, useClass: CustomLazyAPIKeyLoader}
时,它可以工作,但我无法动态设置我的 google 地图 api 密钥。我怎样才能实现我的目标?

应用程序模块

@NgModule({
  imports: [
    ...,
    AgmCoreModule.forRoot({
      apiKey: 'initialKey',
      libraries: ['places']
    }),    
  ],
  declarations: [AppComponent, AdminLayoutComponent, AuthLayoutComponent, PdoLayoutComponent],
  providers: [
    InterceptService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptService,
      multi: true,
    },
    { provide: LocationStrategy, useClass: HashLocationStrategy },
    { provide: MapsAPILoader, useClass: CustomLazyAPIKeyLoader} // I don't get error when I remove this
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

PdoProfileModule(子模块)

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(PdoProfileRoutes),
    FormsModule,
    SharedModule,
    MatTooltipModule,
    MatGoogleMapsAutocompleteModule,
    AgmCoreModule,
  ],
  declarations: [PdoProfileComponent], // this component uses agm-map
})
export class PdoProfileModule {}

custom-apikey-loader.service.ts(这将根据指南动态设置 api)

import { GoogleMapsScriptProtocol, LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral, MapsAPILoader } from '@agm/core';
import { DocumentRef, WindowRef } from '@agm/core/utils/browser-globals.d';
import { Inject, Injectable } from '@angular/core';
import { EnvService } from './env.service';

@Injectable()
export class CustomLazyAPIKeyLoader extends MapsAPILoader {
    private _scriptLoadingPromise: Promise<any>;
    private _config: LazyMapsAPILoaderConfigLiteral;
    private _windowRef: WindowRef;
    private _documentRef: DocumentRef;
    private _key: string;

    constructor(@Inject(LAZY_MAPS_API_CONFIG) config: any, w: WindowRef, d: DocumentRef, private envService: EnvService) {
        super();
        this._config = config || {};
        this._windowRef = w;
        this._documentRef = d;

        //set google map api key
        this.envService.getMapsKey().subscribe((res) => {
          if (res.googleMapsApiKey) {
            this._key = res.googleMapsApiKey;
          }
        })

    }

    load(): Promise<any> {
        if (this._scriptLoadingPromise) {
            return this._scriptLoadingPromise;
        }

        const script = this._documentRef.getNativeDocument().createElement('script');
        script.type = 'text/javascript';
        script.async = true;
        script.defer = true;
        const callbackName: string = `angular2GoogleMapsLazyMapsAPILoader`;
        
        console.log('map key', this._key);
        this._config.apiKey = this._key;
        script.src = this._getScriptSrc(callbackName);
        this._documentRef.getNativeDocument().body.appendChild(script);

        this._scriptLoadingPromise = new Promise((resolve: Function, reject: Function) => {
            (this._windowRef.getNativeWindow())[callbackName] = () => { console.log("loaded"); resolve(); };

            script.onerror = (error: Event) => { reject(error); };
        });


        return this._scriptLoadingPromise;
    }

   //rest of the code is the same from https://gist.github.com/msaxena25/fa59c2130642de3ef6330c6cff2ce6c2
angular angular-module angular-google-maps
1个回答
0
投票

可能是最佳实践

创建一个首先加载的 Angular 模块。在此模块中,从应用程序的服务器获取所有所需的密钥、用户配置文件或任何其他数据,并将这些数据存储在可以同步读取的位置。然后,重定向到应用程序的主模块。对自己放轻松一点。

© www.soinside.com 2019 - 2024. All rights reserved.