While developing my app with the Google Maps library, I encountered an issue either due to an unexplainable delay in creating markers or an unseen asynchronous problem.
Here is a breakdown of the situation: The code retrieves the locations of Electric Charging Stations along a route between starting and ending points, creates Google markers for each station retrieved in JSON format, and adds them to an array. The intention is to later calculate a route with stopovers using these markers (not shown here).
The main problem is that it initiates the calculation method before completing the marker creation process.
To align the results, rather than fetching all the results at once, I implemented a loop that follows this sequence:
- Create a route and extract an encoded polyline from it (for use in the URL)
- Retrieve results
- Create markers, place them on the map, and add them to the array
- Console log completion message ('EV markers creation finished')
Subsequently, it triggers the route calculation process (here displayed as an alert 'calculateAndDisplayRoute method called')
However, in reality, the loop finishes and logs in the console, but the final markers are not created until after the alert is triggered, and only then can you see the markers appear on the map.
You can test out the following code snippet: https://codepen.io/reivilo85k/pen/wvowpab
Below is the problematic code segment (additional code was added to the CodePen example for proper functionality):
chargingPointsMarkers = [];
markerArray = [];
async callbackHandler(startEndPointsArray, calculateAndDisplayRoute): Promise<void> {
await this.setChargingStationsMarkers();
calculateAndDisplayRoute();
}
function calculateAndDisplayRoute() {
alert('calculateAndDisplayRoute method called')
}
async function setChargingStationsMarkers() {
const polylineMarkersArray = await createMarkersArray();
console.log('Polyline Markers created', polylineMarkersArray);
const baseUrl = 'URL REMOVED';
for (let j = 0; j < polylineMarkersArray.length - 1; j++) {
const origin = polylineMarkersArray[j].getPosition();
const destination = polylineMarkersArray[j + 1].getPosition();
const route = await createRoute(origin, destination);
const encodedPolyline = route.overview_polyline;
const queryUrl = baseUrl + '&polyline='+ encodedPolyline + '&distance=50';
await fetch(queryUrl)
.then((response) => response.json())
.then( async (data) => await createChargerPointMarkers(data))
.then (() => {
const k = j + 1;
const l = polylineMarkersArray.length - 1;
if (j === polylineMarkersArray.length - 2) {
console.log('loop ' + k + ' of ' + l);
console.log('EV markers creation finished');
}else{
console.log('loop ' + k + ' of ' + l);
}
});
}
}
async createChargerPointMarkers(jsonChargingPoints): Promise<void> {
// Convert the Json response elements to Google Markers, places them on the Map and pushes them to an array.
for (const item of jsonChargingPoints) {
const LatLng = new google.maps.LatLng(parseFloat(item.AddressInfo.Latitude), parseFloat(item.AddressInfo.Longitude));
const marker = await new google.maps.Marker({
position: LatLng,
map: this.map,
draggable: false,
});
this.markerArray.push(marker);
this.chargingPointsMarkers.push(marker);
}
}
async createRoute(point1, point2): Promise<google.maps.DirectionsRoute> {
// Returns a Google DirectionsRoute object
const directionsService = new google.maps.DirectionsService();
const request = {
origin: point1,
destination: point2,
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC
};
return new Promise(resolve => directionsService.route(request,
(result, status) => {
if (status === 'OK') {
resolve(result.routes[0]);
} else {
window.alert('Directions request failed due to ' + status);
}
})
);
}