I am trying to setup a map using the Places Autocomplete service so I can type an address and plot it on a map. I am using the @googlemaps/js-api-loader
npm package to load.
The version when using Loader
has a different issue/error for each. I've only seen the Autocomplete kind of work on the alpha version and I am using the example from the Google API docs.
weekly
: I get this error on page load: TypeError: google.maps.places.PlaceAutocompleteElement is not a constructor
beta
: Error when I start typing in the search text field: This API project is not authorized to use this API. Places API error: ApiNotActivatedMapError
. I also see this error in the console: Encountered a network request error: PLACES_AUTOCOMPLETE: REQUEST_DENIED: The application is not allowed to use the Place Service.
alpha
: When typing in search, the autocomplete populates with addresses. However when I click on an address, the gmp-placeselect
event is never triggered. But it is hitting the API just fine despite what the beta
version tells me.I've also verified that the URL generated by the js-api-loader
is the same as the example on this page. They are explicitly using the beta
version, but I am getting an API error that it's not enabled. However the fact that it works on the alpha
version makes me question that error. But just in case I have included a screenshot of the APIs enabled for the API_KEY
I am using here. I also tried it with "Don't restrict key" either. That fails as well. This page also tells me I should be using the beta version, but it's rejecting my API calls saying I haven't enabled the API (screenshot below disagrees).
Code is as follows (vue3):
import { Loader } from '@googlemaps/js-api-loader';
const loader = new Loader({
apiKey: 'MY_API_KEY',
version: 'alpha', // weekly, alpha or beta (none work completely)
libraries: ['places']
});
async function initMap() {
// Request needed libraries.
const [{ Map }, { AdvancedMarkerElement }] = await Promise.all([
loader.importLibrary("marker"),
loader.importLibrary("places"),
]);
// Initialize the map.
map.value = new google.maps.Map(document.getElementById("map"), {
center: { lat: -34.397, lng: 150.644 },
zoom: 9,
mapId: "4504f8b37365c3d0",
mapTypeControl: false,
});
let placeAutocomplete =
new google.maps.places.PlaceAutocompleteElement({
componentRestrictions: {country: ['us']},
});
placeAutocomplete.id = "pac-input";
let card = document.getElementById("pac-map");
card.appendChild(placeAutocomplete);
placeAutocomplete.addEventListener('gmp-placeselect', async ({ place }) => {
console.log(place); // NEVER MAKES IT HERE IN ALPHA
});
}
onMounted(async () => {
initMap();
});
A couple of things seem to be going on here:
weekly: the new web-components of the Maps JavaScript API haven't made their way into a stable release (weekly, monthly, quarterly) yet. This includes the PlaceAutocompleteElement
, so that isn't available when using the stable channels
beta: ApiNotActivatedMapError
indicates that there is a problem with the API keys and enabled APIs. As we can see, you already enabled the Places API (New), that - to my understanding - should be enough for the new component. However, can you try if it helps when you enable the legacy places API as well?
alpha: the problem here is that there has been a change regarding the selection event: in the alpha version (as well as in any future stable version) this event is now called gmp-select
instead of gmp-placeselect
(this is mentioned here in the documentation). This is the recommended way handle the events regardless of the version you're using:
async function handlePlaceSelected(place) {
await place.fetchFields({fields: ["displayName", "formattedAddress", "viewport"]});
map.fitBounds(place.viewport);
}
// beta channel
pacEl.addEventListener("gmp-placeselect", async (event) =>
handlePlaceSelected(event.place),
);
// alpha channel and upcoming stable version
pacEl.addEventListener("gmp-select", async (event) =>
handlePlaceSelected(event.placePrediction.toPlace()),
);
As for your code-example:
the destructuring of the result of Promise.all(...)
is wrong. It would have to be:
const [{ Map }, { AdvancedMarkerElement }] = await Promise.all([
loader.importLibrary("maps"),
loader.importLibrary("marker"),
loader.importLibrary("places"),
]);
But since you're not even using the values, you could just leave that away:
await Promise.all([loader.importLibrary("marker"), loader.importLibrary("places")]);