-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add new autocomplete example (#198)
- Loading branch information
1 parent
11fdc13
commit 5176df8
Showing
23 changed files
with
693 additions
and
207 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Autocomplete Examples | ||
|
||
Here you can find a few example implementations of the autocomplete functionality utilizing the Google Places API. | ||
|
||
## Examples | ||
|
||
We have three different implementations to demonstrate how to add autocomplete functionality to your application | ||
|
||
### 1) Google Maps Autocomplete Widget | ||
|
||
When using the [Google Maps Autocomplete widget][autocomplete-widget] you provide an HTML input element of your choice and Google handles all the rest. It will fetch predictions when the user types and it will get the details for a place when the user selects a prediction from the list. | ||
|
||
### 2) Custom Build | ||
|
||
When you need complete control over every aspect of your autocomplete you can choose to build your own by utilizing the [Autocomplete Service][autocomplete-service] for fetching query predictions and the [Places Service][place-details] for fetching the place details. | ||
|
||
When building your own you are completely free but also responsible for the user experience of the autocomplete. You are also responsible for handling the autocomplete session with a [Session token][session-token]. This can easily be overlooked and may lead to unexpected surprises when it comes to billing. | ||
|
||
### 3) Third Party Select Widget | ||
|
||
This is basically the same as the custom build, except for not having to implement the list/dropdown/DOM handling yourself. A lot of third party text box widgets provide functionionality for handling keyboard navigation and focus handling. For the demo we used the [Combobox][combobox] from `react-widgets`. | ||
|
||
## Google Maps API key | ||
|
||
This example does not come with an API key. Running the examples locally requires a valid API key for the Google Maps Platform. | ||
See [the official documentation][get-api-key] on how to create and configure your own key. For this example to work you also need to enable the `Places API` in your Google Cloud Console. | ||
|
||
The API key has to be provided via an environment variable `GOOGLE_MAPS_API_KEY`. This can be done by creating a | ||
file named `.env` in the example directory with the following content: | ||
|
||
```shell title=".env" | ||
GOOGLE_MAPS_API_KEY="<YOUR API KEY HERE>" | ||
``` | ||
|
||
If you are on the CodeSandbox playground you can also choose to [provide the API key like this](https://codesandbox.io/docs/learn/environment/secrets) | ||
|
||
## Development | ||
|
||
Go into the example-directory and run | ||
|
||
```shell | ||
npm install | ||
``` | ||
|
||
To start the example with the local library run | ||
|
||
```shell | ||
npm run start-local | ||
``` | ||
|
||
The regular `npm start` task is only used for the standalone versions of the example (CodeSandbox for example) | ||
|
||
[get-api-key]: https://developers.google.com/maps/documentation/javascript/get-api-key | ||
[autocomplete-widget]: https://developers.google.com/maps/documentation/javascript/place-autocomplete#add-autocomplete | ||
[autocomplete-service]: https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#AutocompleteService.getPlacePredictions | ||
[place-details]: https://developers.google.com/maps/documentation/javascript/reference/places-service#PlacesService.getDetails | ||
[session-token]: https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#AutocompleteSessionToken | ||
[combobox]: https://jquense.github.io/react-widgets/docs/Combobox |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<meta | ||
name="viewport" | ||
content="width=device-width, initial-scale=1.0, user-scalable=no" /> | ||
<title>Autocomplete Examples</title> | ||
<meta name="description" content="Autocomplete Examples" /> | ||
<style> | ||
body { | ||
margin: 0; | ||
font-family: sans-serif; | ||
} | ||
#app { | ||
width: 100vw; | ||
height: 100vh; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div id="app"></div> | ||
<script type="module"> | ||
import '@vis.gl/react-google-maps/examples.css'; | ||
import '@vis.gl/react-google-maps/examples.js'; | ||
import {renderToDom} from './src/app'; | ||
|
||
renderToDom(document.querySelector('#app')); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"type": "module", | ||
"dependencies": { | ||
"@vis.gl/react-google-maps": "*", | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"react-widgets": "^5.8.4", | ||
"vite": "^5.0.4" | ||
}, | ||
"scripts": { | ||
"start": "vite", | ||
"start-local": "vite --config ../vite.config.local.js", | ||
"build": "vite build" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import React, {useState} from 'react'; | ||
import {createRoot} from 'react-dom/client'; | ||
import {APIProvider, ControlPosition, Map} from '@vis.gl/react-google-maps'; | ||
|
||
import ControlPanel from './control-panel'; | ||
import {CustomMapControl} from './map-control'; | ||
import MapHandler from './map-handler'; | ||
|
||
const API_KEY = | ||
globalThis.GOOGLE_MAPS_API_KEY ?? (process.env.GOOGLE_MAPS_API_KEY as string); | ||
|
||
export type AutocompleteMode = {id: string; label: string}; | ||
|
||
const autocompleteModes: Array<AutocompleteMode> = [ | ||
{id: 'classic', label: 'Google Autocomplete Widget'}, | ||
{id: 'custom', label: 'Custom Build'}, | ||
{id: 'custom-hybrid', label: 'Custom w/ Select Widget'} | ||
]; | ||
|
||
const App = () => { | ||
const [selectedAutocompleteMode, setSelectedAutocompleteMode] = | ||
useState<AutocompleteMode>(autocompleteModes[0]); | ||
|
||
const [selectedPlace, setSelectedPlace] = | ||
useState<google.maps.places.PlaceResult | null>(null); | ||
|
||
return ( | ||
<APIProvider apiKey={API_KEY}> | ||
<Map | ||
zoom={3} | ||
center={{lat: 22.54992, lng: 0}} | ||
gestureHandling={'greedy'} | ||
disableDefaultUI={true} | ||
/> | ||
|
||
<CustomMapControl | ||
controlPosition={ControlPosition.TOP} | ||
selectedAutocompleteMode={selectedAutocompleteMode} | ||
onPlaceSelect={setSelectedPlace} | ||
/> | ||
|
||
<ControlPanel | ||
autocompleteModes={autocompleteModes} | ||
selectedAutocompleteMode={selectedAutocompleteMode} | ||
onAutocompleteModeChange={setSelectedAutocompleteMode} | ||
/> | ||
|
||
<MapHandler place={selectedPlace} /> | ||
</APIProvider> | ||
); | ||
}; | ||
|
||
export default App; | ||
|
||
export function renderToDom(container: HTMLElement) { | ||
const root = createRoot(container); | ||
|
||
root.render(<App />); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// NOTE: This requires the alpha version of the Google Maps API and is not yet | ||
// recommended to be used in production applications. We will add this to the example map | ||
// when it reaches GA (General Availability). Treat this as a preview of what's to come. | ||
|
||
import React, {useRef, useEffect, useState} from 'react'; | ||
import {useMapsLibrary} from '@vis.gl/react-google-maps'; | ||
|
||
interface Props { | ||
onPlaceSelect: (place: google.maps.places.PlaceResult | null) => void; | ||
} | ||
|
||
// This is an example of the new "PlaceAutocomplete" widget. | ||
// https://developers.google.com/maps/documentation/javascript/place-autocomplete-new | ||
export const PlaceAutocompleteNew = ({onPlaceSelect}: Props) => { | ||
const [placeAutocomplete, setPlaceAutocomplete] = useState<Node | null>(null); | ||
const containerRef = useRef<HTMLDivElement>(null); | ||
const places = useMapsLibrary('places'); | ||
|
||
useEffect(() => { | ||
if (!places) return; | ||
// @ts-expect-error Using an alpha feature here. The types are not up to date yet | ||
setPlaceAutocomplete(new places.PlaceAutocompleteElement()); | ||
}, [places]); | ||
|
||
useEffect(() => { | ||
if (!placeAutocomplete) return; | ||
|
||
placeAutocomplete.addEventListener( | ||
'gmp-placeselect', | ||
// @ts-expect-error This new event has no types yet | ||
async ({place}: {place: google.maps.places.Place}) => { | ||
await place.fetchFields({ | ||
fields: ['displayName', 'formattedAddress', 'location', 'viewport'] | ||
}); | ||
|
||
onPlaceSelect(place.toJSON()); | ||
} | ||
); | ||
|
||
containerRef.current?.appendChild(placeAutocomplete); | ||
}, [onPlaceSelect, placeAutocomplete]); | ||
|
||
return <div className="autocomplete-container" ref={containerRef} />; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React, {useRef, useEffect, useState} from 'react'; | ||
import {useMapsLibrary} from '@vis.gl/react-google-maps'; | ||
|
||
interface Props { | ||
onPlaceSelect: (place: google.maps.places.PlaceResult | null) => void; | ||
} | ||
|
||
// This is an example of the classic "Place Autocomplete" widget. | ||
// https://developers.google.com/maps/documentation/javascript/place-autocomplete | ||
export const PlaceAutocompleteClassic = ({onPlaceSelect}: Props) => { | ||
const [placeAutocomplete, setPlaceAutocomplete] = | ||
useState<google.maps.places.Autocomplete | null>(null); | ||
const inputRef = useRef<HTMLInputElement>(null); | ||
const places = useMapsLibrary('places'); | ||
|
||
useEffect(() => { | ||
if (!places || !inputRef.current) return; | ||
|
||
const options = { | ||
fields: ['geometry', 'name', 'formatted_address'] | ||
}; | ||
|
||
setPlaceAutocomplete(new places.Autocomplete(inputRef.current, options)); | ||
}, [places]); | ||
|
||
useEffect(() => { | ||
if (!placeAutocomplete) return; | ||
|
||
placeAutocomplete.addListener('place_changed', () => { | ||
onPlaceSelect(placeAutocomplete.getPlace()); | ||
}); | ||
}, [onPlaceSelect, placeAutocomplete]); | ||
|
||
return ( | ||
<div className="autocomplete-container"> | ||
<input ref={inputRef} /> | ||
</div> | ||
); | ||
}; |
Oops, something went wrong.