Syn
Syn

Reputation: 1128

google maps api autocomplete on blur/focusout?

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

Answers (2)

Ferhat
Ferhat

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

MrUpsidown
MrUpsidown

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

Related Questions