Google Maps: Add custom data for markers
Feature Request
Plugin
Google Maps
Description
Often devs need to add custom data (a specific database entry ID, etc.) to markers and receive them when the marker is clicked. E.g. an entry id to load more details from an API for the clicked marker dynamically.
This stackoverflow reply suggests three ways for adding customInfo to markers:
var markerA = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(0, 0),
customInfo: "Marker A"
});
var markerB = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(-10, 0)
});
markerB.customInfo = "Marker B";
var markerC = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(-20, 0)
});
markerC['customInfo'] = "Marker C";
Platform(s)
All
Preferred Solution
Add option like customData:{}which can be appended to map.addMarker().
When the marker is clicked, it will be transmitted here:
async setMarkerListeners(
mapId: string,
markerId: string,
marker: google.maps.Marker,
): Promise<void> {
marker.addListener('click', () => {
this.notifyListeners('onMarkerClick', {
...
title: marker.getTitle(),
customData: marker.getCustomData()
});
});
}
https://github.com/ionic-team/capacitor-plugins/blob/main/google-maps/src/web.ts#L319
I'm not a typescript pro yet, guess there need to be some modifications on other files as well.
Alternatives
Storing marker IDs and connect them with custom data in JS (marker manager).
Additional Context
Related to https://github.com/ionic-team/capacitor-plugins/issues/1133
Thx very much in advance for looking into this!
+1 this, I had a tough time transitioning from AGM maps to capacitor maps because of this issue.
Previous, i could just pass the whole marker click event to another component, with all the data already inside the Marker.
+1
+1 for the ability to specify a markerData object or at least a single customMarkerId property in the addMarker() data structure that will be round-tripped back in thesetOnMarkerClickListener callback
Since marker id is pretty random due to a bug #1222 , there is a solution for this by creating a service which stores your add-info into a map and the marker id as its value. Later you just need to get that data witch the marker id returned from e.g. onMarkerClick function.
In my opinion a custom markerId or even a marker field "metadata" like the community plugin has (https://capacitor-community.github.io/google-maps/#/api?id=markerpreferences) are not needed, doing so would add complexity to the project for something that not all devs need in their project, second as you can read in the community plugin documentation this had led to again other problems in the past hence the warning they added and most importantly you can achieve what you want today without it... here is an example of what I did in my project:
to add data to a marker you don't need extra fields in the marker object itself, it is enough if the markers have a working ID (which currently is not the case on iOS, hence this PR), so now you get your list of markers from the database, something like [{ markerDatabaseId: 1, markerDatabaseName: 'foo' }, { markerDatabaseId: 2, markerDatabaseName: 'bar' }], then you use addMarkers (https://capacitorjs.com/docs/apis/google-maps#addmarkers) which returns you a list of mapMarkersIds, so now you iterate through you list from database and for each one you add the mapMarkerId (that you got from addMarkers), something like this:
const myMarkersFromDatabase = await fetchMarkersFromDatabase()
const addMarkersResult = await googleMap.addMarkers(googleMapMarkers)
const myFinalMarkersList: IMyCustomMarker[] = []
addMarkersResult.map((googleMapMarkerId, index) => {
const markerData = myMarkersFromDatabase[index]
const myMarkerWithMapId = { googleMapMarkerId, ...markerData }
myFinalMarkersList.push(myMarkerWithMapId)
})
now you have an array like this: [{ markerDatabaseId: 1, markerDatabaseName: 'foo', googleMapMarkerId: 'm1' }, { markerDatabaseId: 2, markerDatabaseName: 'bar', googleMapMarkerId: 'm2' }]
and finally somewhere else in your code, if you want to get the data of a marker for example because you are using setOnMarkerClickListener (https://capacitorjs.com/docs/apis/google-maps#setonmarkerclicklistener), you do something like this:
const markerData= myFinalMarkersList.find(marker => {
return marker.googleMapMarkerId === markerClickId
})
Same problem, how to match clicked marker and markers array?
For anyone, this is how you do it atm, but be aware that this only works with my patch from #1222.
/** Example interface of YOUR marker/class. */
interface Marker {
id: string;
lat: number;
lng: number;
}
/** Just to check if marker with this id was already created. */
const markerIds = new Set<string>();
/** Holds all markers with its native id for later re-use. */
const markers = new Map<string, Marker>();
/**
* Add a new marker.
*/
async function addMarker(marker: Marker) {
if (!markerIds.has(marker.id)) {
const markerId = await map.addMarker({
lat: marker.lat,
lng: marker.lng,
});
this.markerIds.add(marker.id);
this.markers.set(markerId, marker);
}
}
// Example how you can handle it later...
await map.setOnMarkerClickListener((marker) => {
const markerId = marker.markerId.toString()
const marker = markers.get(markerId)
})