網站搜尋

typescript - 從 Mapbox 彈出視窗重定向到 Angular 元件


我正在使用 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 類添加到 <a> 標籤後,使用 document.getElementByClassName("some-test-class")[0].addEventListener('click',()=>{console.log("hello!"});,以及與 document. 類似的方法。 如這裡和第三個回答中建議的那樣使用 getElementById(),我得到的結果是「Cannot read property 'addEventListener' of undefined」。我也嘗試了這裡列出的第二種方法,但似乎也不起作用。我還看到了一些更複雜的解決方案,涉及到 ComponentFactoryResolver(這個問題中被接受的答案),但在試圖弄清楚它之前,只是為了解決看起來很簡單的問題,我想先問問有沒有更簡單、直接的方法。或者有人可以建議為什麼我之前的嘗試失敗了。

答案#1

在使用 mapboxgl.Source 和 mapboxgl.Layer 處理您的資料時,還有另一個選項。

  1. 將您的資料轉換成 GeoJson,使彈出視窗的動態內容儲存在 features 的 properties 中。
  2. 使用你轉換過的 GeoJson 數據創建一個 mapboxgl.Source,其 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 中的單一 Feature 大致上應該長這樣

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

答案#2

我最終使用這裡的第一個答案解決了它。我的程式碼現在是:

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/router 的 Router 類型。即使我使用 ionViewWillEnter,這個方法似乎也能運作,所以我不確定選擇哪個生命週期鉤子在這裡是否會有差別。