You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:05:05