Angular 17.x中正确获取@angular/google-map组件引用的方法
Angular 17.3.5 + @angular/google-maps 获取组件引用问题及解决方案
问题描述
使用^17.3.5版本的@angular/google-maps和Angular框架,尝试通过模板引用变量获取google-map组件:
<google-map #map mapId="map" height="100%" width="100%" [options]="options"></google-map>
组件中通过@ViewChild获取引用后,在ngAfterViewInit中调用时触发错误:
ngAfterViewInit(): void { this.map.googleMap!.fitBounds({ north: 43.516034, south: 43.423021, east: 5.471529, west: 5.456153, }); }
报错信息:
ERROR TypeError: Cannot read properties of undefined (reading 'googleMap')
当前可行方案的疑问
使用mapInitialized事件能正常获取google.maps.Map原生实例,但无法直接拿到GoogleMap组件实例,不确定该方式是否存在弊端:
模板代码:
<google-map #map (mapInitialized)="initMap($event)" mapId="map" height="100%" width="100%" [options]="options"></google-map>
组件代码:
map!: google.maps.Map initMap(map: google.maps.Map) { this.map = map; this.initAdvancedMarkers() } async initAdvancedMarkers() { const {AdvancedMarkerElement} = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary; let markers = [ { lat: 43.516034, lng: 5.471529, }, { lat: 43.523021, lng: 5.456153, }, { lat: 43.423021, lng: 5.456153, }, ]; let bounds = new google.maps.LatLngBounds(); // 设置标记并调整视野以显示所有标记 markers.forEach((marker: any) => { new AdvancedMarkerElement({ map: this.map, position: marker }); bounds.extend( new google.maps.LatLng(marker.lat, marker.lng) ); }); this.map.fitBounds(bounds); }
正确实现方向
方案1:mapInitialized事件结合ViewChild获取组件实例
mapInitialized是官方推荐的地图初始化完成回调时机,此时组件实例和原生地图实例均已就绪,可以同时获取两者:
import { Component, ViewChild } from '@angular/core'; import { GoogleMap } from '@angular/google-maps'; @Component({ // 组件元数据 }) export class YourMapComponent { @ViewChild('map') mapComponent!: GoogleMap; mapInstance!: google.maps.Map; initMap(map: google.maps.Map) { this.mapInstance = map; // 此时可安全访问组件的googleMap属性,与原生实例一致 console.log(this.mapComponent.googleMap); this.initAdvancedMarkers(); } async initAdvancedMarkers() { // 标记初始化代码保持不变 this.mapInstance.fitBounds(bounds); } }
该方式无弊端,属于官方设计的标准用法,能确保所有地图操作都在实例完全就绪后执行。
方案2:监听组件的googleMap$可观察对象
如果想通过ViewChild直接等待地图初始化,可利用组件提供的googleMap$可观察对象,它会在原生实例就绪后发出值:
import { Component, ViewChild, AfterViewInit } from '@angular/core'; import { GoogleMap } from '@angular/google-maps'; import { take } from 'rxjs'; @Component({ // 组件元数据 }) export class YourMapComponent implements AfterViewInit { @ViewChild(GoogleMap) mapComponent!: GoogleMap; ngAfterViewInit(): void { this.mapComponent.googleMap$ .pipe(take(1)) .subscribe(mapInstance => { mapInstance.fitBounds({ north: 43.516034, south: 43.423021, east: 5.471529, west: 5.456153, }); this.initAdvancedMarkers(mapInstance); }); } async initAdvancedMarkers(mapInstance: google.maps.Map) { // 使用传入的原生实例执行标记初始化 } }
报错原因说明
ngAfterViewInit触发时,Angular仅完成了组件视图的渲染,但Google Maps原生实例是异步加载(需加载外部脚本、完成地图初始化),此时googleMap属性尚未赋值,因此会出现未定义错误。
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

