Coder Social home page Coder Social logo

wellyshen / use-places-autocomplete Goto Github PK

View Code? Open in Web Editor NEW
1.2K 10.0 62.0 5.37 MB

๐Ÿ˜Ž ๐Ÿ“ React hook for Google Maps Places Autocomplete.

Home Page: https://use-places-autocomplete.netlify.app

License: MIT License

TypeScript 80.13% JavaScript 5.73% Shell 0.30% HTML 7.45% SCSS 6.38%
react hook places autocomplete places-autocomplete google-places google-places-api google-maps google-maps-api google-place-autocomplete

use-places-autocomplete's People

Contributors

allcontributors[bot] avatar csandman avatar dependabot-preview[bot] avatar dependabot[bot] avatar isoaxe avatar kylekirkby avatar lkaric avatar orbiteleven avatar ravenhurst avatar reharik avatar tyeetale avatar viniciusueharaweb avatar wellyshen avatar xerxes-j avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

use-places-autocomplete's Issues

Why was getDetails signature changed?

Hi, here
a43e1b1#diff-39b2554fd18da165b59a6351b1aafff3714e2a80c1435f2de9706355b4d32351L70
there is a change. It used to be the case that if you passed in just the place_id it would work or if you passed in the "suggestion" it would pull the place_id out of it and it would work.
Now neither of those work you have pass in an object with a camelcased placeId on it. This is not good. It is a breaking change for no advantage that I can tell. I you want the sig to take string | {place_id: string} | {placeId: string} then that's find but why break it for those using it the old way?

Not a bug

This is not a bug, this just a thank you guys, this was very helpfull

Query caching

It would be great that this library offers out of the box caching of the results so we don't request new queries for the same inputed search criteria within the same user session. This could potentially help saving costs.

Why yours basic example doesn't work for me

Hello,

I'm trying to use yours basic example to be able to understand how to use your module in my system but seems nothing to work. I don't have any console errors and have no idea what wrong actually. I hope you can help me to understand what I'm missing.

Thank you and the code

import { useLoadScript } from '@react-google-maps/api';
import useOnclickOutside from 'react-cool-onclickoutside';
import usePlacesAutocomplete, {
  getGeocode,
  getLatLng,
} from 'use-places-autocomplete';

const libraries = ['places'];

export default function AutoCompletePlaces() {
  console.log('IS IT RUNNING ????');

  const API_KEY = process.env.GOOGLE_PLACES_API_KEY;
  const { isLoaded, loadError } = useLoadScript({
    googleMapsApiKey: API_KEY,
    libraries,
  });

  console.log('LOADED ????', isLoaded, loadError);

  const {
    ready,
    value,
    suggestions: { status, data },
    setValue,
    clearSuggestions,
  } = usePlacesAutocomplete({
    // requestOptions: {
    //   /* Define search scope here */
    // },
    debounce: 300,
  });
  console.log(status, data);
  const ref = useOnclickOutside(() => {
    // When user clicks outside of the component, we can dismiss
    // the searched suggestions by calling this method
    clearSuggestions();
  });

  const handleInput = e => {
    // Update the keyword of the input element
    setValue(e.target.value);
  };

  const handleSelect = ({ description }) => () => {
    console.log(description);
    // When user selects a place, we can replace the keyword without request data from API
    // by setting the second parameter to "false"
    setValue(description, false);
    clearSuggestions();

    // Get latitude and longitude via utility functions
    getGeocode({ address: description })
      .then(results => getLatLng(results[0]))
      .then(({ lat, lng }) => {
        console.log('๐Ÿ“ Coordinates: ', { lat, lng });
      })
      .catch(error => {
        console.log('๐Ÿ˜ฑ Error: ', error);
      });
  };

  const renderSuggestions = () =>
    data.map(suggestion => {
      const {
        place_id,
        structured_formatting: { main_text, secondary_text },
      } = suggestion;

      return (
        <li key={place_id} onClick={handleSelect(suggestion)}>
          <strong>{main_text}</strong> <small>{secondary_text}</small>
        </li>
      );
    });

  return loadError || !isLoaded ? (
    <div>FAIL</div>
  ) : (
    <div ref={ref}>
      <input
        value={value}
        onChange={handleInput}
        disabled={!ready}
        placeholder="Where are you going?"
      />
      {/* We can use the "status" to decide whether we should display the dropdown or not */}
      {status === 'OK' && <ul>{renderSuggestions()}</ul>}
    </div>
  );

Support loading google maps api via a library

Feature Request

Describe the Feature

Thanks for the awesome work.
We are using load-google-maps-api
to load google maps api with useEffect when the component loads. Because there is no script that we can set callback name and useEffect runs after component loads, the ready state returned by usePlacesAutocomplete is always false and it stays that way until the component is "remounted" (e.g navigate away and back). The workaround we found is setting a fake callback name as a state and pass it to usePlacesAutocomplete, once the load google maps promise resolves we set the callback name to undefined, which triggers the effect calling init function in use-places-autocomplete (because callbackName is one of the dependencies of that effect). This works fine but it's coupled to the library's internal implementation. Is there a better way to solve this or could you add support for loading google maps api via third party library?

Describe the Solution You'd Like

I think if the usePlacesAutocomplete hook could expose the init function for users to call it whenever the google maps api is loaded, the above issue would be solved.

Ability to "setFields" with the getDetails function

When the getDetails function is called on a place id, it returns all the fields which you are charged for on each API call. Google Maps API autocomplete documentation has the following value to limit the data returned:
autocomplete.setFields(["address_components", "geometry", "icon", "name"]);
https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete

Are these options able to be passed into the getDetails function?

Missing language request parameter

Bug Report

Describe the Bug

The API specification lists a language parameter, but this library isn't including it as a valid option (not sure if it was an omission or if this parameter was recently added).
https://developers.google.com/places/web-service/autocomplete

How to Reproduce

Try to add the language parameter to requestOptions on a TS project, it will complain.

Expected Behavior

language parameter should be accepted in requestOptions and it should be send to Google Autocomplete services

Your Environment

  • OS: macOs
  • Browser Chrome
  • Version of use-places-autocomplete: 1.3.10

Cannot include sessionToken in request

To reduce costs, Google requires autocomplete requests include a session token: https://developers.google.com/places/web-service/usage-and-billing

Passing in a simple string (for example, generated by uui()) passes typecheck, but then fails when making the request with the error: "in property sessionToken: not an instance of AutocompleteSessionToken", name: "InvalidValueError""

The top-level export file does not include the necessary class to create an AutocompleteSessionToken, meaning it is impossible to include a sessionToken in the request (without modifying this library)

requestOptions seems to get ignored

Bug Report

Describe the Bug

passing the requestOptions doesn't seem to work. Looking at the google doc https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#AutocompletionRequest it should be possible to restrict results from an specific country by passing the property componentRestrictions.country with the country code. found here https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#ComponentRestrictions

I'm pretty new with react so maybe this isn't bug but maybe I have done something wrong in my code.

How to Reproduce

inside requestOptions, simply put

componentRestrictions: {
      country: 'sv'
   }

CodeSandbox Link

https://codesandbox.io/s/useplacesautocomplete-x-reach-ui-forked-qo84h
in the same demo as you already have. Look at line 25 in this forked sandbox

Expected Behavior

I expect this code to only show results from the country SV (sweden)

componentRestrictions: {
      country: 'sv'
   }

Your Environment

  • Device: [e.g. MacBook Pro, iPhone12]
  • OS: [Windows]
  • Browser: [Chrome]
  • Version: [88.0]

I really like this! Except from this it works grate in my app!
If this is not a bug, I would really appreciate help to get it to work !

How to display "powered by Google" attribution?

I've checked the documentation but I can't find how to display the attribution. Is there any way to turn this on?

Google docs says it's just an image. So, should I grab the attribution image from the docs and serve it from my server or is there anyway to turn this on?

TypeScript: `suggestions.data` is of type `any`

Bug Report

Describe the Bug

When using the autocomplete in TypeScript, suggestions.data is an array of type any. I believe this to be because AutocompletePrediction is any since it doesn't exist in the index.d.ts file.

How to Reproduce

import usePlacesAutocomplete from 'use-places-autocomplete';

export const AutocompleteLocation = (): JSX.Element => {
  const {
      suggestions: {
        data,
      },
      setValue,
    } = usePlacesAutocomplete({
      requestOptions: {
        componentRestrictions: { country: 'us' },
      },
      callbackName: 'loadPlaceAutocomplete',
      debounce: 300,
    });

    /**
     * The below will result in "Unsafe member access .description on an any value." since `data` is an array of `any`.
     * Note that I am seeing this when using typescript-eslint. 
     */
    data.map((suggestion) => suggestion.description);
};

Expected Behavior

That suggestions.data is properly typed instead of any

Screenshots

image

Your Environment

  • Device: MacBook Pro (2017)
  • OS: macOS Catalina version 10.15.7 (19H114)
  • Browser: N/A
  • Version: 1.7.0

Additional Information

Any other information about the problem here.

Setting types in requestOptions results in Invalid Request

I'm trying to get only countrynames from Places API using types in requestOptions.

Accordingly to this documentation it should be possible
image

Google's RequestOptions Doc: https://developers.google.com/maps/documentation/places/web-service/supported_types#table3

However when I execute this code here:
image

I get this error:
image

Expectate behaviour:
I expect it to show me only countrynames on proper input and nothing on bad input (when country does not start with searchstring it wont show anything.

Am I using it in a wrong way or is it really a bug?

Lazily Initializing The Hook

First of all, thanks for this library.
I'm trying to use this hook to initialize the Google api, however I have one question.
Where does useGoogleMapsApi() imported from?

import usePlacesAutocomplete from "use-places-autocomplete";

const App = () => {
  const { init } = usePlacesAutocomplete({
    initOnMount: false, // Disable initializing when the component mounts, default is true
  });

  const [loading] = useGoogleMapsApi({
    library: "places",
    onLoad: () => init(), // Lazily initializing the hook when the script is ready
  });

  return <div>{/* Some components... */}</div>;
};

Cors and invalid hook problem

Hello. I have an "Invalid hook call" and "Cors origin" problem with this library. How do you think, how can I fix it?

How to fix refused to load the script https://maps.googleapis.com/maps/api/...because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-inline' 'unsafe-eval'

Hi everyone,

I got a issue and can not using autocomplete place, I have try to fix it but still not resolve it
In env local, I load script google map not get any issue, but env production I got the following error.

Refused to load the script 'https://maps.googleapis.com/maps/api/js?v=weekly&key=xxxxxyyyyyyddฤ‘d&libraries=places&language=vi' because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-inline' 'unsafe-eval' www.googletagmanager.com connect.facebook.net www.googleadservices.com www.google-analytics.com googleads.g.doubleclick.net onesignal.com tpc.googlesyndication.com". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

This is how I try, but still can not fix it:

<meta httpEquiv="Content-Security-Policy" content="script-src 'self' 'unsafe-eval' 'unsafe-inline' developers.google.com maps.googleapis.com https://www.googletagmanager.com https://connect.facebook.net https://www.googleadservices.com https://www.google-analytics.com https://googleads.g.doubleclick.net https://onesignal.com https://tpc.googlesyndication.com;" />

And don't know where the other sources are called from, because I don't use it like: www.googletagmanager.com, connect.facebook.net, www.googleadservices.com, www.google-analytics.com, googleads.g.doubleclick .net,...

Looking forward to all the helpers. Thanks all.

Source:

  • NextJS: 11.1.2

Where i put this script?? index.html, index.js, app.js ?

GitHub Issues are reserved for Bug reports and Feature requests. Support requests that are created as issues are likely to be closed. We want to make sure you are able to find the help you seek. Please take a look at the following resources.

Coding Questions

If you have a coding question related to React, it might be better suited for Stack Overflow. It's a great place to browse through frequent questions about using React, as well as ask for help with specific questions.

https://stackoverflow.com/questions/tagged/react

Support Forums

There are many online forums which are a great place for discussion about best practices and application architecture.

https://reactjs.org/community/support.html#popular-discussion-forums

Default location based on user's current location

Feature Request

Describe the Feature

A default location shown on the autocomplete input as soon as ui rendered.

Describe the Solution You'd Like

If user's location is shared via browser geolocation api use that lat lang to display default location, user can change that obviously if needed.
It should enabled via a config variable.
e.g
showCurrentLocationOnLoad: true | false

Cache returns incorrect data after changing componentRestrictions

Bug Report

Suppose we have a component where a user can select a country then the autocomplete only shows addresses from that country:

  const [country, setCountry] = useState('GB');
  const { suggestions, setValue  } = usePlacesAutocomplete({
    requestOptions: {
      componentRestrictions: { country },
    },
  });

When we search for 123, it returns some British addresses - so far so good. Now if we setCountry('US') and type 123 again it returns the cached British addresses instead of doing a new search for US addresses.

Which service SKU does component use ?

Due to expected high volume of request goign to Places API i was wondering what kind of SKU do you use under the hood to make request some are free and some are whoping $17 per 1k requests.

See more : Basic SKU

Overall its such a nice component good job.

Reverse geocoding with location in getGeocode

Hello,

Feature Request

Describe the Feature

According to Google's documentation, the geocoder API allows doing that with location (LatLng) option. It would be nice to have it supported by GetGeocode too.

My use case is: I only have a LatLnt param and need to get the point's metadata.

Describe the Solution You'd Like

I want to expand the GetGeocode's interface to have that option and add additional parameters validation.

I'm asking about before doing any contribution, according to the project's recommendations.

Thank you.

[Docs] Usage of requestOptions - how to get country/city etc in the suggestion

Thank you for the awesome package!

I skimmed through the docs [1, 2, and 3] I'm still a bit confused as per how to request the types in order to retrieve the country, city etc in the returned suggestions.

So the question/suggestion/request:

It would be very helpful if the docs would include at least one basic example of how to use requestOptions instead of just having a placeholder /* Define search scope here */

PS.
And in case my gut feels is right and the requestOptions are not at all meant to alter the response for the formatting, then perhaps any pointers on how one could go about this? But would still be nice to have an example that explains the purpose of requestOptions in more detail. :)

Thanks again for this package! ๐Ÿ™Œ๐Ÿผ

Sources:
https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#AutocompletionRequest
https://developers.google.com/places/supported_types#table3

Moving {lat, lng} object between components as props

Hi Welly!

I'm making a web app where I'd like to pass the {lat, lng} object from the getGeocode Custom Hook to another component as a props. That component will these use each coordinate as a parameter to a Rest API request.

getGeocode({ address: description })
			.then((results) => getLatLng(results[0]))
			.then(({ lat, lng }) => {
				console.log('๐Ÿ“ Coordinates: ', { lat, lng })
			})
			.catch((error) => {
				console.log('๐Ÿ˜ฑ Error: ', error)
			})

I think the part where I am getting hung up is the React's unidirectional data flow. I am having trouble getting the {lat, lng} object "back up" out of my AddressInput.js component and into my "root" component App.js, where I then want to pass {lat, lng} into another component as props.

I realize that I am probably thinking about the app's structure the wrong way. Should I instead be calling the API in a useEffect Hook? Thanks in advance for any advice you may be able to provide!

Async load script in component

I'm trying to async load script only in one component. I get not errors but ready is always false. My code:

const PlaceAutocomplete =( ) => {

  const {
    ready,
    value,
    suggestions: { status, data },
    setValue,
    clearSuggestions
  } = usePlacesAutocomplete({   
    callbackName: 'initMap',
    debounce: 300
  });

  useEffect(()=> {
    const createScriptLoadMap = () => {
      if (!window.initMap) {
        var index = window.document.getElementsByTagName("script")[0];
        var script = window.document.createElement("script");
        script.src =
          "https://maps.googleapis.com/maps/api/js?key=******&libraries=places&callback=initMap"; // 
        script.async = true;
        script.defer = true;
        index.parentNode.insertBefore(script, index);
        window.initMap = true;
      }
    };
   createScriptLoadMap();
  },[]) 

  // rest of code

Google requires you to display the required logos and attributions

Bug Report

Hey, the demo code doesn't have the Google logo and attributions and it violates the API use policy

Expected Behavior

If this is out of the demo scope, we must at least add some text to make this clear.

Screenshots

Add screenshots to help explain your problem.

Your Environment

  • OS: macOS
  • Browser: Chrome
  • Version: 1.2.3

Additional Information

https://developers.google.com/maps/documentation/javascript/places-autocomplete#policies

Multiple components

Hi, I am using this package for creating a custom component but when I repeat my custom component 2 times the first component does not work because has the same class names as the second component. Please any idea?

image

GLatLng not exported

Bug Report

GLatLng not exported.

Describe the Bug

Trying to use

usePlacesAutocomplete({
debounce: 300,
requestOptions: {
location: new GLatLng(19.419224, -99.171446),
},
})

But can't access GLatLng class since it's not exported.

How to Reproduce

Run this code:

`import usePlacesAutocomplete, GLatLng, from "use-places-autocomplete"

usePlacesAutocomplete({
debounce: 300,
requestOptions: {
location: new GLatLng(19.419224, -99.171446),
},
})`

GLatLng is expected but not exported in the module :(

Expected Behavior

GLatLng should be expected

Your Environment

  • OS: macOS
  • Browser Chrome
  • Version of use-places-autocomplete: v1.0.4

Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.

Bug Report

Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.
Sometimes the suggestions are not showing and console logs this error. Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.

No clear steps to reproduce.

Expected Behavior

It should work even session storage throws an error

Screenshots

Screen Shot 2021-07-26 at 9 07 03 AM

Your Environment

  • Browser: [Chrome Mobile]
  • Version 87.0.4280
  • Operating System - Android
  • Version 8.1.0

Debounce not working when passing `requestOptions`

Bug Report

Describe the Bug

Debounce not working when using requestOptions

How to Reproduce

  1. Pass requestOptions in the hook:
usePlacesAutocomplete({
    requestOptions: {},
    debounce: 300
});

Expected Behavior

But it works when there's no requestOptions:

usePlacesAutocomplete({
    debounce: 300
});

Load google apis script in the component

I tried to load the google api script in the component using useEffect

useEffect(() => {
    loadGoogleMaps();
}, []);

const loadGoogleMaps = async () => {
   const google = await loadScript(
      'https://maps.googleapis.com.......',
     'google'
   );
};

The script loads just after or at the same time as my component, and suddenly the 1st time the autocomplete does not work.

I can put the load script in index.tsx or app.tsx, but I prefer to keep it in the same component as autocomplete !

Thanks !

Google Maps JavaScript API warning: RetiredVersion

Bug Report

Describe the Bug

Hi. Thank you for this library. It appears that the Google Maps Javascript API might be outdated, see error message:

Google Maps JavaScript API warning: RetiredVersion https://developers.google.com/maps/documentation/javascript/error-messages#retired-version

How to Reproduce

Simply use the hook in normal form operation.

Expected Behavior

Would be great if the warning was removed.

Thanks.

Missing features in demo

The documentation refers to a demo/code which is more UX rich including "a keyword clear button, search history"

Having implemented the code example I don't see these two features, so I'm wondering if I'm missing something here? Are there any code examples available for these two features?

Thanks

"requestOptions" parameter should be casted to "google.maps.places.AutocompleteOptions" instead of "google.maps.places.AutocompletionRequest"

I started implementing your library which is really well done by the way but I've noticed that "requestOptions" parameter has the wrong type which forbids me to set "requestOptions.strictBounds = true". Changing type should allow me to fix my issue which is a very import feature to us (see https://developers.google.com/maps/documentation/javascript/reference/places-widget?hl=en#AutocompleteOptions).

Thank you in advance!

getZipCode utility function

Feature Request

Describe the Feature

I think "getZipCode" utility function would be very helpful for me and everyone else. For example, I use your hook on my address field and I try to auto-populate zip code on another field.

Currently, I get results from "getGeocode" and iterate through them and manually take out "postal_code" from "address_components" array.

I hope you understand :)

How that loading works of suggestions

Hello,

I have a query about the loading status in suggestions

const {
    ready,
    value: autocompleteValue,
    suggestions: { data, status, loading },
    clearSuggestions,
    setValue,
  } = usePlacesAutocomplete({
    debounce: 3000,
  });

This loading is very fast and the spinner I attached to show on loading appears for a millisecond and I would like to understand how to delay this or if there is a better way of doing it?

I want to show up my loader spinner

const isLoading = () => {
    return loading ? <CircularProgress color="inherit" size={20} /> : null;
  };

Thank you :)

Implement sessionToken to reduce costs even further

Feature Request

Describe the Feature

It's already great that you implemented debouncing to reduce API calls, but Google will nevertheless charge per each of these request. However, there's a parameter called sessionToken that can be sent to group one autocompletion and be charged only once.

These are some links about this feature:

Places API documentation
https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#AutocompleteSessionToken

They mentioned it when they introduced the pricing changes
https://cloud.google.com/maps-platform/user-guide/pricing-changes/

In the example for the query here it's all lowercased (so sessiontoken instead of sessionToken)
https://developers.google.com/places/web-service/usage-and-billing#ac-with-details-session

Thank you for making this React hook, by the way!

Add componentRestrictions for Geocoding

Feature Request

Describe the Feature

Right now the getGeocode method only accepts an address or a place id.
The Google Geocoding service can accept a component restrictions parameter to restricted results to a specific area.

Describe the Solution You'd Like

Update the getGeocode method to accept component restrictions as PlaceAutocomplete.

Additional Information

If you have no time to do it, I can try to find some time to create a pull request this week.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.