google places library without map

Was making a custom address autocomplete for a sign up form.

import {useState, useRef, useEffect } from 'React'

function AutoCompleteInput(){

const [predictions, setPredictions] = useState([]);
const [input, setInput] = useState('');
const [selectedPlaceDetail, addSelectedPlaceDetail] = useState({})
const predictionsRef = useRef();


useEffect(
()=>{
      try {
        autocompleteService.current.getPlacePredictions({ input }, predictions => {
          setPredictions(predictions);
        });
      } catch (err) {
       // do something
      }
    }
}, [input])

const handleAutoCompletePlaceSelected = placeId=>{
 if (window.google) {
      const PlacesService = new window.google.maps.places.PlacesService(predictionsRef.current);
      try {
        PlacesService.getDetails(
          {
            placeId,
            fields: ['address_components'],
          },
         place => addSelectedPlaceDetail(place)
        );
      } catch (e) {
        console.error(e);
      }
    }
}

return (
  <>
   <input onChange={(e)=>setInput(e.currentTarget.value)}
    <div ref={predictionsRef}
     { predictions.map(prediction => <div onClick={ ()=>handleAutoCompletePlaceSelected(suggestion.place_id)}> prediction.description </div> )
   }
   </div>
  <>
 )
}

So basically, you setup the autocomplete call, and get back the predictions results in your local state.

from there, map and show the results with a click handler that will do the follow up request to the places services with access to the getDetails method for the full address object or whatever fields you want.

you then save that response to your local state and off you go.


If you want to get location data from a place_id you can do it using the Geocoder class:Here the documentation. With this class you can pass a place_id to the method geocode() and get coordinates and other location data.


As documented the PlacesService accepts as argument either a map or an node where to render the attributions for the results.

So you only have to use the node (a node being an html element) instead of the map.

Please note: hiding the attributions violates the places-policies(also hiding the map when used as argument, because the map will show the attributions)

This also may be interesting to you: Google places API does this violate the TOC?


Example: in a nutshell

If you're using jQuery:

var service = new google.maps.places.PlacesService($('#tag-id').get(0));

If plain Javascript:

var service = new google.maps.places.PlacesService(document.createElement('div'));

Then carry on as usual with the rest of the example code:

  service.nearbySearch(request, callback);

Example: using details returned

Live demo of this example on jsFiddle.

Note: This example uses jQuery.

<ul class="reviews__content" id="reviews__content">
</ul>
<div id="service-helper"></div>

<script async defer
src="https://maps.googleapis.com/maps/api/js?key=GOOGLE_API_KEY_HERE&libraries=places&callback=getRelevantGoogleReviews">
</script>
<script type="text/javascript">
   window.getRelevantGoogleReviews = function(){
     var service = new google.maps.places.PlacesService($('#service-helper').get(0)); // note that it removes the content inside div with tag '#service-helper'

     service.getDetails({
         placeId: 'ChIJAwEf5VFQqEcRollj8j_kqnE'  // get a placeId using https://developers.google.com/places/web-service/place-id
        }, function(place, status) {
            if (status === google.maps.places.PlacesServiceStatus.OK) {
              var resultcontent = '';
              for (i=0; i<place.reviews.length; ++i) {
                //window.alert('Name:' + place.name + '. ID: ' + place.place_id + '. address: ' + place.formatted_address);
                resultcontent += '<li class="reviews__item">'
                resultcontent += '<div class="reviews__review-er">' + place.reviews[i].author_name + '</div>';
                var reviewDate = new Date(place.reviews[i].time * 1000);
                var reviewDateMM = reviewDate.getMonth() + 1;
                var reviewDateFormatted = reviewDate.getDate() + '/' + reviewDateMM + '/' + reviewDate.getFullYear(); 
                resultcontent += '<div class="reviews__review-date">' + reviewDateFormatted + '</div>';
                resultcontent += '<div class="reviews__review-rating reviews__review-rating--' + place.reviews[i].rating +'"></div>';
                if (!!place.reviews[i].text){
                  resultcontent += '<div class="reviews__review-comment">' + place.reviews[i].text + '</div>';
                }
                resultcontent += '</li>'
              }
              $('#reviews__content').append(resultcontent);
            }
        });
    }
</script>

Just seen Man asking in a comment above How to initialise the places service without initialising a map? so I thought I would add it here.

placesService = new google.maps.places.PlacesService($('#predicted-places').get(0));

You will need to create an html element with that id first though.