Reputation: 1128
So I am using the google maps api to fill out some information on the backend but if the user doesn't 'click' on a dropdown option, the backend never gets populated with the data.
I found a workaround on stack overflow here: link but nothing fires on blur/focusout.
let address = document.getElementById('inputAddress');
(function pacSelectFirst(input) {
// store the original event binding function
var _addEventListener = (input.addEventListener) ? input.addEventListener : input.attachEvent;
function addEventListenerWrapper(type, listener) {
// Simulate a 'down arrow' keypress on hitting 'return' when no pac suggestion is selected,
// and then trigger the original listener.
if (type == "keydown" || type == 'blur') {
var orig_listener = listener;
listener = function(event) {
var suggestion_selected = $(".pac-item-selected").length > 0;
// if [enter] or [tab] is pressed
if ((event.which == 13 || event.which == 9) && !suggestion_selected) {
var simulated_downarrow = $.Event("keydown", {
keyCode: 40,
which: 40
});
orig_listener.apply(input, [simulated_downarrow]);
}
orig_listener.apply(input, [event]);
};
}
_addEventListener.apply(input, [type, listener]);
}
input.addEventListener = addEventListenerWrapper;
input.attachEvent = addEventListenerWrapper;
var autocomplete = new google.maps.places.Autocomplete(input);
})(address);
I understand what the code is doing. When you click tab or enter, it simulates a down arrow press. I tried adding in a listener for blur but nothing works. The event still gets fired but it doesn't select or update.
Would love some help regarding this situation. Thank you!
Upvotes: 1
Views: 3131
Reputation: 58
Did you check if you have multiple dropdowns bound to the input field? Other instances of
var autocomplete = new google.maps.places.Autocomplete(input);
somewhere else? It turned out we had three of them. After taking two of them out, your solution worked for me.
Upvotes: 1
Reputation: 22497
inputAddress
being your autocomplete input, you can do the following:
// Trigger search on blur
document.getElementById('inputAddress').onblur = function () {
google.maps.event.trigger(this, 'focus', {});
google.maps.event.trigger(this, 'keydown', {
keyCode: 13
});
};
Or with a google maps event listener:
// Trigger search on blur
google.maps.event.addDomListener(document.getElementById("inputAddress"), 'blur', function() {
google.maps.event.trigger(this, 'focus', {});
google.maps.event.trigger(this, 'keydown', {
keyCode: 13
});
});
This alone will interfere with a user selecting a suggestion via mouse click. So to prevent that, you need to make a few more checks. Below is a full example. Read the code comments for more info.
If you use jQuery in your project, look at this answer which does exactly the same.
function initialize() {
var ac = new google.maps.places.Autocomplete(
(document.getElementById('inputAddress')), {
types: ['geocode']
});
ac.addListener('place_changed', function() {
var place = ac.getPlace();
if (!place.geometry) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
console.log("No details available for input: '" + place.name + "'");
return;
}
console.log("You selected: '" + place.formatted_address + "'");
});
// Trigger search on blur
google.maps.event.addDomListener(document.getElementById("inputAddress"), 'blur', function() {
// Find the pac-container element
var pacContainer = nextByClass(this, 'pac-container');
// Check if we are hovering on one of the pac-items
// :hover propagates to parent element so we only need to check it on the pac-container
// We trigger the focus and keydown only if :hover is false otherwise it will interfere with a place selection via mouse click
if (pacContainer.matches(':hover') === false) {
google.maps.event.trigger(this, 'focus', {});
google.maps.event.trigger(this, 'keydown', {
keyCode: 13
});
}
});
}
function hasClass(elem, cls) {
var str = " " + elem.className + " ";
var testCls = " " + cls + " ";
return (str.indexOf(testCls) != -1);
}
function nextByClass(node, cls) {
while (node = node.nextSibling) {
if (hasClass(node, cls)) {
return node;
}
}
return null;
}
#inputAddress {
width: 300px;
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&callback=initialize&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk" async defer></script>
<input id="inputAddress" placeholder="Enter your address" type="text"></input>
Upvotes: 1