我正在使用
@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 模块。在此模块中,从应用程序的服务器获取所有所需的密钥、用户配置文件或任何其他数据,并将这些数据存储在可以同步读取的位置。然后,重定向到应用程序的主模块。对自己放轻松一点。