Reputation: 107
I am developing a mobile application using Ionic and Angular. I have several Mapbox markers rendered on the map, each of it displaying a popop on click with custom content. I would like the button in the popup to redirect the user to the page that contains more details about that specific location. My code is the following:
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
}
Of course that the ready-to-use method would be using the href
attribute of the <a>
tag, but I would like to use some Angular-specific routing method to route to the respective page of each business displayed on the map (the route should depend on the ${key}). So far I have tried using document.getElementByClassName("some-test-class")[0].addEventListener('click',()=>{console.log("hello!"});
after adding the some-test-class
class to the <a>
tag and something similar with document.getElementById()
as suggested here and in the 3rd answer here and I get "Cannot read property 'addEventListener' of undefined". I also tried the second approach listed here but this does not seem to work either. I also saw more complex solutions, that involve ComponentFactoryResolver
(the accepted answer of this question) but before trying to wrap my head around it just to solve what seems to be something trivial, I thought of asking for an easier, more-direct approach. Or maybe for a suggestion of why my previous attempts failed.
Upvotes: 2
Views: 1743
Reputation: 169
There is another option when using mapboxgl.Source
and mapboxgl.Layer
for your data.
properties
.mapboxgl.Source
with type: "geojson"
using your transformed GeoJson data.mapboxgl.Layer
with the created source and your preferred style.setDOMContent
method. See below for some prototyping.This allows you to fully interact between the Popup and Angular (not just the routing).
<!-- 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);
});
}
A single Feature in the GeoJson FeatureCollection should more or less look like this
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [
data[key].location.coord.lng,
data[key].location.coord.lat
]
},
properties: {
key: key,
name: data[key].name
// ...
}
}
Upvotes: 3
Reputation: 107
I eventually solved it using the first answer from here. My code now:
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
}
where router
is of type Router
from @angular/router
. This thing seems to work even if I use ionViewWillEnter
, so I am not sure if the choice of a lifecycle hook makes a diference here.
Upvotes: 1
Reputation: 141
You cannot call any htmlElement in ionViewWillEnter as the view isn't created. Try to put this code into ionViewDidEnter instead.
Upvotes: 0