Events other than 'place_changed' for Google Maps Autocomplete
Asked Answered
R

5

54

I have an app that currently fires correctly on place_changed.

However, I want to branch search to behave differently when a user has selected an autocomplete entry, and when they have entered text on their own without the assistance of autocomplete.

What kind of event listener should I use to make the distinction? I cannot find any documentation on other events for Google Maps Autocomplete.

what I have now:

var gmaps = new google.maps.places.Autocomplete($("#searchproperties").get(0), 
{ types: ['geocode'], componentRestrictions: {country: 'us'} });

google.maps.event.addListener(gmaps, 'place_changed', function () {
    //FIRE SEARCH
});
Repudiate answered 24/8, 2015 at 22:55 Comment(0)
C
13

There is only one documented event in the Google Maps Javascript API v3 for the google.maps.places.Autocomplete class, place_changed

You can add standard HTML event listeners to it (not sure if that will affect the Autocomplete functionality).

Chrystal answered 24/8, 2015 at 23:12 Comment(3)
The problem I have encountered is that the blur and change events fire before the Google place_changed event. This makes it difficult to know what actually happened.Yesteryear
@Yesteryear Were you able to resolve your issue? I am having the same exact problem.Repeated
I suppose OP's question can be understood as "What [...] should I use to make the distinction?", in which case, this doesn't provide a solution at all.Audriaaudrie
A
11

This comes down to checking whether you receive a place.geometry object, as it is shown in their official example. As simple as that!

function initialize() {

  var ac = new google.maps.places.Autocomplete(
    (document.getElementById('autocomplete')), {
      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.
      // Do anything you like with what was entered in the ac field.
      console.log('You entered: ' + place.name);
      return;
    }

    console.log('You selected: ' + place.formatted_address);
  });
}

initialize();
#autocomplete {
  width: 300px;
}
<input id="autocomplete" placeholder="Enter your address" type="text"></input>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
Audriaaudrie answered 27/9, 2018 at 10:22 Comment(0)
S
5

(Updated answer — Oct 18th 2018 UTC)

The place_changed documentation says:

If the user enters the name of a Place that was not suggested by the control and presses the Enter key, or if a Place Details request fails, the PlaceResult contains the user input in the name property, with no other properties defined.

So (as I mentioned in my comment), we can check if the property name is the only property in the PlaceResult object retrieved via Autocomplete.getPlace(). See and try the code snippet below:

(If the API key doesn't work, use your own.)

var gmaps = new google.maps.places.Autocomplete($("#searchproperties").get(0), 
{ types: ['geocode'], componentRestrictions: {country: 'us'} });

google.maps.event.addListener(gmaps, 'place_changed', function () {
  var place = gmaps.getPlace(),
    has_name = ( place && undefined !== place.name ),
    count = 0;

  // Iterates through `place` and see if it has other props.
  $.each( place || {}, function(){
    if ( count > 1 ) {
      // No need to count all; so let's break the iteration.
      return false;
    }
    count++;
  });

  if ( has_name && count < 2 ) {
    $('#test').html( 'You didn\'t make a selection and typed: ' + place.name );
  } else {
    $('#test').html( 'You selected: ' + place.formatted_address );
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBMPpy3betC_QCBJtc3sC4BtEIYo4OYtPU&libraries=places"></script>

<input id="searchproperties" placeholder="Search places">
<div id="test"></div>
Swarts answered 25/9, 2018 at 6:53 Comment(5)
You definitely don't need all that... see my answer for details.Audriaaudrie
@Audriaaudrie At least, the doc did say, if the user did not explicitly make a selection from the suggested places found (if any), the name property would be the keyword the user typed into the Autocomplete field. That's the main point of the answer. And we could also simply check if the place has name as the only property (as the doc says; hence I checked undefined === place.formatted_address), and if yes, then it's a manual "selection", assuming the request succeeded.Swarts
Sure, this is a valid part of your answer. Why are they checking on the place.geometry and not on another property is not explained anywhere afaik but I believe that a valid place always has geometry, while other parameters might be missing (this is my interpretation). In any case, your code seems to work, but you can achieve the same with much less code ;)Audriaaudrie
Yep, you're right. I did see the geometry and all the other possible properties, but I guess I was focused on "if formatted_address is present, then it's not a manual selection or a failed request". =) Anway, thank you for the edit, though I intentionally didn't include it since there's already the same link in the answer.Swarts
Actually, thanks @MrUpsidown. I updated the answer. Hopefully it will help someone. ;)Swarts
T
3

If you add your own input handler (for example catching CR after user entering his own text), autocomplete and your function may call your method back to back. My solution is to use throttle to avoid the repeated call:

$('#sell_address_input').keyup(function(e){ if(e.keyCode==13){throttle(addressEntered(),1000)}});

....

function throttle(callback, limit) {
    var wait = false;             // Initially, we're not waiting
    return function () {          // We return a throttled function
        if (!wait) 
        {                         // If we're not waiting
          callback.call();        // Execute users function
          wait = true;            // Prevent future invocations
          setTimeout(function () 
          {                       // After a period of time
            wait = false;         // And allow future invocations
          }, limit);
        }
    }
}
Tackling answered 27/10, 2017 at 7:3 Comment(0)
C
0

This is quite an old question but i propose a solution that could be lot simplier than what i read here.

The 'place_changed' event only fires when a user actually select a suggestion from Google's list.

So as long as the user did not select a suggestion, you can consider that the text entered in the input is not a google's place result.

From here, you could consider 'place-changed' as a kind of 'click' event, using a boolean to store the current state

function initializeAutocomplete(id) {  
    var element = document.getElementById(id);    
    if (element) {    
        var autocomplete = new google.maps.places.Autocomplete(element, { types: ['geocode','establishment'], componentRestrictions: {country: ['fr']} });
        google.maps.event.addListener(autocomplete, 'place_changed', function(){
            var place = this.getPlace();
            console.log("A result from "+id+" was clicked !");
            for (var i in place.address_components) {    
                var component = place.address_components[i];    
                for (var j in component.types) {  
                    var type_element = document.getElementById(component.types[j]);      
                    if (type_element) {        
                        type_element.value = component.long_name;
                    }    
                }  
            }               
        });         
    }
}
Couturier answered 17/6, 2019 at 12:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.