Reputation: 1604
Google Places API Web Service has a 1000 request per day quota limit for non-billed accounts. When using the search box autosuggestion feature providing multiple places for each key press, this limit will be reached fairly quickly.
<input id="pac-input" class="controls" type="text" placeholder="Search Box">
<div style="height:100%; width:100%;position:absolute;">
<div id="map"></div>
</div>
<script>
window.onload = initAutocomplete;
function initAutocomplete() {
var my_position = new google.maps.LatLng(51.163375, 10.447683);
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 51.163375, lng: 10.447683},
disableDoubleClickZoom: true,
zoom: 9,
mapTypeId: 'roadmap'
});
// Create the search box and link it to the UI element.
var input = document.getElementById('pac-input');
var searchBox = new google.maps.places.SearchBox(input);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
// Bias the SearchBox results towards current map's viewport.
map.addListener('bounds_changed', function() {
searchBox.setBounds(map.getBounds());
});
var markers = [];
var crowdMarker = new google.maps.Marker({
position: my_position,
map: map
});
google.maps.event.addListener(map, 'dblclick', function(e){
var positionDoubleClick = e.latLng;
crowdMarker.setPosition(positionDoubleClick);
var lat = crowdMarker.getPosition().lat();
var lng = crowdMarker.getPosition().lng();
});
// Listen for the event fired when the user selects a prediction and retrieve
// more details for that place.
google.maps.event.addDomListener(searchBox, 'keydown', function (e) {
if (e.keyCode == 13) {
e.preventDefault();
}
});
searchBox.addListener('places_changed', function() {
var places = searchBox.getPlaces();
if (places.length == 0) {
return;
}
// Clear out the old markers.
markers.forEach(function(marker) {
marker.setMap(null);
});
markers = [];
// For each place, get the icon, name and location.
var bounds = new google.maps.LatLngBounds();
places.forEach(function(place) {
if (!place.geometry) {
console.log("Returned place contains no geometry");
return;
}
var icon = {
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(25, 25)
};
// Create a marker for each place.
markers.push(new google.maps.Marker({
map: map,
icon: icon,
title: place.name,
position: place.geometry.location
}));
if (place.geometry.viewport) {
// Only geocodes have viewport.
bounds.union(place.geometry.viewport);
} else {
bounds.extend(place.geometry.location);
}
});
map.fitBounds(bounds);
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=myAPIKey&libraries=places"
async defer></script>
Things I've tried include setting a bound to the SearchBox to limit the suggestions to a set area, as well as adding a delay within the keydown section.
Can anyone suggest a way to be able to throttle or delay the autosuggestion appearing, and therefore sending fewer requests?
Upvotes: 6
Views: 3723
Reputation: 10858
You can monkey-patch the input
event on the input element to intercept it and throttle, debounce, or stop it there.
Below is an example of throttling, but the idea can easily be extended to fit your use case:
function getPlacesFromInput(input, fn) {
// patching happens here
const restore = throttleEventListener("input", input, 750);
const api = new google.maps.places.Autocomplete(input, {
/* your options */
});
const listener = api.addListener("place_changed", function () {
fn(api.getPlace()); // place selected
});
return function _cleanUp() {
restore();
listener.remove();
};
}
function throttleEventListener(eventType, element, time) {
// Keep the original method to be un-patched later, if desired
const originalAddEventListener = element.addEventListener;
element.addEventListener = function (type, listener, options) {
if (type === eventType) {
// You can intercept it here:
const debouncedListener = _.throttle(listener, time);
originalAddEventListener.call(
this,
type,
debouncedListener,
options
);
} else {
// Every other event is treated as normal this way
originalAddEventListener.call(this, type, listener, options);
}
};
// Returns a function with which we can undo the patching
return function _cleanUp() {
element.addEventListener = originalAddEventListener;
};
}
Beware of using the this
keyword when patching these functions. You can learn how to do it properly here: https://stackoverflow.com/a/20279485/832447
Upvotes: 1
Reputation: 32178
I'm afraid the current implementation of autocomplete and search box in places library of Maps JavaScript API doesn't allow to throttle or delay requests programmatically. You can see a feature request in Google issue tracker for this:
https://issuetracker.google.com/issues/35823678
Please star this feature request to add your vote. The only workaround I can think of is implementing your own autocomplete element that uses a google.maps.places.AutocompleteService
class and where you will be able to control a frequency of requests sent to AutocompleteService
.
https://developers.google.com/maps/documentation/javascript/reference#AutocompleteService
Upvotes: 2