I faced the same problem. Here is what I did, working just fine, multiple inputs supported
Solution code
typescript version
interface DestroyablePACOptions {
input: HTMLInputElement;
dropdownTimeoutMs ? : number;
options ? : google.maps.places.AutocompleteOptions;
onPlaceChange ? : () => void;
}
export interface DestroyablePACWrapper {
instance: google.maps.places.Autocomplete;
destroy: () => void;
}
let instanceIndex = 0;
export function destroyableAutocomplete({
input,
options,
dropdownTimeoutMs = 500,
onPlaceChange,
}: DestroyablePACOptions): DestroyablePACWrapper {
const instance = new google.maps.places.Autocomplete(input, options);
// capturing the new dropdown that we want to destroy then
let dropdown: HTMLElement | null = null;
// seems like we need to wait for some time until PAC creates the dropdown, not sure what could be the perfect timeout
setTimeout(
() => {
// looking for a new dropdown (we will add the DOM attribute to make the solution compatible with multiple inputs/dropdowns)
dropdown = document.querySelector('.pac-container:not([dpac-captured])');
if (dropdown !== null) {
// marking it so our next calls could skip it as already handled
dropdown.setAttribute('dpac-captured', '');
}
},
// every timeout is 1ms longer than the previous one just to make sure that simultaneous calls won't conflict around DOM
dropdownTimeoutMs + instanceIndex++,
);
// attaching the 'place_changed' handler (optional) so we could take care of its removal later.
// We will also return the PAC instance, so you can still do it on your own,
// but in this case - don't forget to unsubscribe your own listeners when calling the .destroy()
let placeChangedListener: google.maps.MapsEventListener | null = null;
if (typeof onPlaceChange === 'function') {
placeChangedListener = instance.addListener('place_changed', onPlaceChange);
}
return {
instance,
destroy() {
// removing the listener (if we created one)
placeChangedListener ? .remove();
// cleaning up the instance (maybe it will also remove all the other/custom listeners, hopefully, but not sure)
google.maps.event.clearInstanceListeners(instance);
// removing the DOM dropdown
dropdown ? .remove();
},
};
}
javascript version
let instanceIndex = 0;
function destroyableAutocomplete({
input,
options,
dropdownTimeoutMs = 500,
onPlaceChange,
}) {
const instance = new google.maps.places.Autocomplete(input, options);
// capturing the new dropdown that we want to destroy then
let dropdown = null;
// seems like we need to wait for some time until PAC creates the dropdown, not sure what could be the perfect timeout
setTimeout(
() => {
// looking for a new dropdown (we will add the DOM attribute to make the solution compatible with multiple inputs/dropdowns)
dropdown = document.querySelector('.pac-container:not([dpac-captured])');
if (dropdown !== null) {
// marking it so our next calls could skip it as already handled
dropdown.setAttribute('dpac-captured', '');
}
},
// every timeout is 1ms longer than the previous one just to make sure that simultaneous calls won't conflict around DOM
dropdownTimeoutMs + instanceIndex++,
);
// attaching the 'place_changed' handler (optional) so we could take care of its removal later.
// We will also return the PAC instance, so you can still do it on your own,
// but in this case - don't forget to unsubscribe your own listeners when calling the .destroy()
let placeChangedListener = null;
if (typeof onPlaceChange === 'function') {
placeChangedListener = instance.addListener('place_changed', onPlaceChange);
}
return {
instance,
destroy() {
// removing the listener (if we created one)
placeChangedListener?.remove();
// cleaning up the instance (maybe it will also remove all the other/custom listeners, hopefully, but not sure)
google.maps.event.clearInstanceListeners(instance);
// removing the DOM dropdown
dropdown?.remove();
},
};
}
Call example:
const dpac = destroyableAutocomplete({
input: document.getElementById("inp"),
options: {
// some options, just for example
// https://developers.google.com/maps/documentation/javascript/reference/places-widget?authuser=1#AutocompleteOptions
fields: ["formatted_address", "name"], //, "geometry", "icon", "icon_background_color", "icon_mask_base_uri"],
strictBounds: false,
types: ["geocode"], // geocode, address, establishment, see https://developers.google.com/maps/documentation/javascript/supported_types?authuser=1
componentRestrictions: {
country: ["us", "ca"],
},
},
});
// ...
setTimeout(() => {
dpac.destroy();
}, 1000);