typescript - Presmerovanie na Angular komponent z Mapbox popupu


Vyvíjam mobilnú aplikáciu pomocou Ionic a Angular. Na mape mám vykreslených niekoľko značiek Mapbox, z ktorých každá zobrazuje popup po kliknutí s vlastným obsahom. Chcel by som, aby tlačidlo v popupe presmerovalo používateľa na stránku, ktorá obsahuje viac informácií o konkrétnom mieste. Môj kód je nasledujúci:

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
  }

Samozrejme, že pripravená na použitie metóda by bola použiť atribút href v značke <a>, ale rád by som použil nejakú Angular-špecifickú metódu routovania na presmerovanie na príslušnú stránku každého podniku zobrazeného na mape (trasa by mala závisieť od $ {key}). Zatiaľ som skúšal použiť document.getElementByClassName("some-test-class")[0].addEventListener('click',()=>{console.log("hello!"}); po pridaní triedy some-test-class do značky <a> a niečo podobné s document. getElementById() ako je navrhnuté tu a v 3. odpovedi tu a dostávam „Cannot read property 'addEventListener' of undefined“. Tiež som vyskúšal druhý prístup uvedený tu, ale ani to akosi nefunguje. Tiež som videl zložitejšie riešenia, ktoré zahŕňajú ComponentFactoryResolver (prijatá odpoveď na túto otázku), ale predtým, než sa pokúsim to celé pochopiť len na vyriešenie niečoho, čo sa zdá byť triviálne, som si myslel, že sa opýtam na jednoduchší, priamejší prístup. Alebo možno na návrh, prečo moje predchádzajúce pokusy zlyhali.

Odpoveď č. 1

Existuje ďalšia možnosť pri používaní mapboxgl.Source a mapboxgl.Layer pre vaše údaje.

  1. Preveďte svoje údaje do formátu GeoJson tak, aby boli dynamický obsah pre vyskakovacie okná uložené v properties prvkov.
  2. Vytvorte mapboxgl.Source s type: "geojson" pomocou vašich transformovaných dát GeoJson.
  3. Vytvorte mapboxgl.Layer s vytvoreným zdrojom a vaším preferovaným štýlom.
  4. Pridajte do šablóny komponentu pop-up kontajner, na ktorý sa potom odkazuje v metóde setDOMContent. Nižšie nájdete niekoľko ukážok prototypovania.

Toto vám umožňuje plne interagovať medzi Popupom a Angularom (nie len smerovanie).

<!-- 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);
  });
}

Jedna funkcia v kolekcii funkcií GeoJson by mala viac-menej vyzerať takto

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

Odpoveď č. 2

Nakoniec som to vyriešil použitím prvej odpovede odtiaľto. Môj kód teraz:

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
  }

kde router je typu Router z @angular/router. Zdá sa, že toto funguje aj keď použijem ionViewWillEnter, takže si nie som istý, či výber životného cyklu robí v tomto prípade rozdiel.