从 Mapbox 弹出窗口重定向到 angular 组件

Redirect to angular component from Mapbox popup

我正在使用 Ionic 和 Angular 开发移动应用程序。我在地图上呈现了几个 Mapbox 标记,每个标记在点击时显示一个带有自定义内容的弹出窗口。我希望弹出窗口中的按钮将用户重定向到包含有关该特定位置的更多详细信息的页面。我的代码如下:

ionViewWillEnter(){
    this.businessService
    .getBusinessCoords()
    .subscribe(data=>{
      for(const key in data){
        let popup = new mapboxgl.Popup({
          className:'popup-class'
        }).setHTML(
            `<div>
            <img src= ${data[key].profile_picture} width="150">
            <b style="text-align: center;"> ${data[key].name}</b><br>
            <i>${data[key].location.address}</i><br>
            <a id="${key}">Tap to see availble offers!</a>
            </div>
            `
          )
        new mapboxgl.Marker({
          color:"#cc0000",
          draggable: false
        }).setLngLat([data[key].location.coord.lng, data[key].location.coord.lat])
          .setPopup(popup)
          .addTo(this.map);
      }
    })//end subscribe
  }

当然,即用型方法是使用 <a> 标记的 href 属性,但我想使用一些 Angular 特定的路由方法路由到地图上显示的每个商家的相应页面(路由应取决于 ${key})。到目前为止,我已经尝试在将 some-test-class class 添加到 <a> 标签之后使用 document.getElementByClassName("some-test-class")[0].addEventListener('click',()=>{console.log("hello!"}); 并且按照建议 here and in the 3rd answer here and I get "Cannot read property 'addEventListener' of undefined". I also tried the second approach listed but this does not seem to work either. I also saw more complex solutions, that involve ComponentFactoryResolver (the accepted answer of document.getElementById() 类似的东西)但是在试图全神贯注解决看似微不足道的问题之前,我想到了寻求一种更简单、更直接的方法。或者也许是关于为什么我以前的尝试失败的建议。

您不能在 ionViewWillEnter 中调用任何 htmlElement,因为尚未创建视图。 尝试将此代码放入 ionViewDidEnter 中。

我最终使用 here 的第一个答案解决了它。我现在的代码:

ionViewDidEnter(){
    this.businessService
    .getBusinessCoords()
    .subscribe(data=>{
      for(const key in data){
        const popupContent = document.createElement('div');
        popupContent.innerHTML = `<img src= ${data[key].profile_picture} width="150">
                                  <b style="text-align: center;"> ${data[key].name}</b><br>
                                  <i>${data[key].location.address}</i><br>`;
        const atag = document.createElement('div');
        atag.innerHTML = `<a id="${key}">Tap to see availble offers!</a>`
        popupContent.appendChild(atag); 
        atag.addEventListener('click', (e)=>{
          console.log('Button was clicked' + key);
          this.router.navigateByUrl('/foodrevolution/profile')
        })
        let popup = new mapboxgl.Popup({
        }).setDOMContent(popupContent); 
          
        new mapboxgl.Marker({
          color:"#cc0000",
          draggable: false
        }).setLngLat([data[key].location.coord.lng, data[key].location.coord.lat])
          .setPopup(popup)
          .addTo(this.map);
      }
    })//end subscribe
  }

其中 router 是来自 @angular/routerRouter 类型。即使我使用 ionViewWillEnter,这个东西似乎也能正常工作,所以我不确定生命周期挂钩的选择是否在这里有所不同。

使用 mapboxgl.Sourcemapboxgl.Layer 作为数据时还有另一个选项。

  1. 将您的数据转换为 GeoJson,以便将弹出窗口的动态内容存储在特征中 properties
  2. 使用转换后的 GeoJson 数据创建 mapboxgl.Source with type: "geojson"
  3. 使用创建的源和您喜欢的样式创建 mapboxgl.Layer
  4. 在您的组件模板中添加一个弹出容器,然后在 setDOMContent 方法中引用该容器。请参阅下面的一些原型。

这允许您在 Popup 和 Angular 之间完全交互(而不仅仅是路由)。

<!-- component.html -->
<div #popupContainer class="popup-container">
  <div *ngIf="popup">
    <img [src]="popup.profile_picture" width="150">
    <b style="text-align: center;">{{ popup.name }}</b><br>
    <i>{{ popup.location.address }}</i><br>
    <a routerLink="/foodrevolution/profile">Tap to see availble offers!</a>
  </div>
</div>
// component.ts
@ViewChild("popupContainer") popupContainer: any;
popup: any;

ionViewDidEnter() {
  this.businessService
    .getBusinessCoords()
    .subscribe((data) => {
      const geoJson = toGeoJson(data);
      this.map.getSource("source-id").setData(geoJson);
    });
  this.map.on("click", "points-layer", (e) => {
    const coordinates = e.features[0].geometry.coordinates.slice();
    this.popup = e.features[0].properties;
    new mapboxgl.Popup()
      .setLngLat(coordinates)
      .setDOMContent(this.popupContainer.nativeElement)
      .addTo(this.map);
  });
}

GeoJson FeatureCollection 中的单个特征应该大致如下所示

{
  type: "Feature",
  geometry: {
    type: "Point",
    coordinates: [
      data[key].location.coord.lng,
      data[key].location.coord.lat
    ]
  },
  properties: {
    key: key,
    name: data[key].name
    // ...
  }
}