angular - 如何在 Angular 2 中加载谷歌地图服务
问题描述
如官方文档中所述,我设法延迟加载Angular 的内置 Google Maps 组件:
export class GoogleMapsDemoComponent {
apiLoaded: Observable<boolean>;
geoCoder: any;
constructor(httpClient: HttpClient) {
this.apiLoaded = httpClient.jsonp('https://maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE', 'callback')
.pipe(
map(() => true),
catchError(() => of(false)),
);
}
ngOnInit(): void {
this.apiLoaded.subscribe(() => this.initGeoCoder());
}
initGeoCoder() {
this.geoCoder = new google.maps.Geocoder();
}
}
如果组件被多次初始化,我现在会遇到错误。
You have included the Google Maps JavaScript API multiple times on this page. This may cause unexpected errors.
因此,我想将 Google Script 的加载移至专用服务,并将其注入到所有需要它的组件中。
GitHub repo 中有一个讨论证实了这种方法:
您应该能够重构 httpClient.jsonp('https://maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE', 'callback') 和周围的 api 加载到服务中,以便它可以充当一个单例并防止多个负载。请注意,您需要将 providedIn: 'root' 添加到您的 @Injectable 中,这样它就不会为每个模块创建一个实例,从而为每个实例加载 api。
虽然我没有设法正确地做到这一点,但我经常收到以下错误消息,当 Google 脚本尚未加载时似乎会出现:
ERROR ReferenceError: google is not defined
服务:
export class GeoService {
apiLoaded: Observable<boolean>;
constructor(private http: HttpClient) {
this.apiLoaded = this.http
.jsonp(
'https://maps.googleapis.com/maps/api/js?key=API_KEY',
'callback'
)
.pipe(
map(() => true),
catchError((error) => of(error))
);
}
}
零件:
export class GoogleMapsDemoComponent {
apiLoaded: Observable<boolean>;
geoCoder: any;
constructor(geo: GeoService) {}
ngOnInit(): void {
this.geo.apiLoaded.subscribe(() => this.initGeoCoder());
}
initGeoCoder() {
this.geoCoder = new google.maps.Geocoder();
}
}
我的服务位于一个共享模块中,该模块被导入到组件的模块中。我还尝试在同一个模块中使用服务,以确保我没有搞砸导入,但我收到了相同的错误消息。
谁能告诉我我在这里缺少什么?
解决方案
我最终结合了将谷歌地图api加载到angular2的最佳方法是什么?和https://github.com/angular/components/issues/21665:
地理服务.ts:
geocode(
request: google.maps.GeocoderRequest
): Observable<google.maps.GeocoderResult[]> {
return new Observable<google.maps.GeocoderResult[]>((observer) => {
if (!this.geocoder) {
this.geocoder = new google.maps.Geocoder();
}
this.geocoder.geocode(request, (results, status) => {
// need to manually trigger ngZone because "geocode" callback is not picked up properly by Angular
this.ngZone.run(() => {
if (status === google.maps.GeocoderStatus.OK) {
// if status is "OK", the response contains a valid GeocoderResponse.
observer.next(results);
observer.complete();
} else {
observer.error(status);
}
});
});
});
}
loadGoogleMaps(url: string, id: string, callback): void {
if (!document.getElementById(id)) {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.id = id;
if (callback) {
script.addEventListener(
'load',
(e) => {
callback(null, e);
},
false
);
}
document.head.appendChild(script);
}
}
零件:
ngAfterViewInit() {
this.geo.loadGoogleMaps(environment.googleMapsURL, 'google-map', () => {
this.initGeoCoder();
});
geoDataFromAddress(
address: google.maps.GeocoderRequest['address']
): Observable<google.maps.GeocoderResult> {
return this.geo
.geocode({ address: address.toLocaleLowerCase() })
.pipe(map((results) => results[0]));
}
推荐阅读
- java - 在休眠时仅保留基类的字段
- security - 如何在 ZAP html 报告中排除不必要的 URL
- swing - 使用带有kotlin插件的gradle构建swing程序,需要-include-runtime
- haskell - 如何使用镜头修改匹配条件的元素?
- javascript - 在 Javascript 生成的页面上正确调用 window.onload
- python - python特征提取:AttributeError:'list'对象没有属性'lower'
- linq - 如何对 IQueryable 方法进行分组
- python - Django - 设置 AUTH_USER_MODEL
- memory-management - VxWorks 内存管理(无法理解)
- android - 与 android studio 共享的 Apk 在某些设备上不起作用