Interfejs Place Autocomplete Data API umożliwia programowe pobieranie prognozowanych lokalizacji, aby tworzyć dostosowane środowiska autouzupełniania z większą kontrolą niż w przypadku widżetu autouzupełniania. Z tego przewodnika dowiesz się, jak korzystać z interfejsu Place Autocomplete Data API do wysyłania żądań autouzupełniania na podstawie zapytań użytkowników.
Poniższy przykład przedstawia uproszczoną integrację funkcji wpisywania z wyprzedzeniem. Wpisz zapytanie, np. „pizza” lub „poke”, a potem kliknij, aby wybrać odpowiedni wynik.
Prośby o autouzupełnianie
Żądanie autouzupełniania przyjmuje ciąg wejściowy zapytania i zwraca listę prognoz miejsc. Aby wysłać żądanie autouzupełniania, wywołaj funkcję fetchAutocompleteSuggestions()
i przekaż żądanie z wymaganymi właściwościami. Właściwość input
zawiera ciąg znaków do wyszukania. W typowym zastosowaniu ta wartość jest aktualizowana w miarę wpisywania zapytania przez użytkownika. Żądanie powinno zawierać sessionToken
, który jest używany do celów rozliczeniowych.
Poniższy fragment kodu pokazuje tworzenie treści żądania i dodawanie tokena sesji, a następnie wywoływanie funkcji fetchAutocompleteSuggestions()
w celu uzyskania listy PlacePrediction
.
// Add an initial request body. let request = { input: "Tadi", locationRestriction: { west: -122.44, north: 37.8, east: -122.39, south: 37.78, }, origin: { lat: 37.7893, lng: -122.4039 }, includedPrimaryTypes: ["restaurant"], language: "en-US", region: "us", }; // Create a session token. const token = new AutocompleteSessionToken(); // Add the token to the request. // @ts-ignore request.sessionToken = token;
Ograniczanie podpowiedzi autouzupełniania
Domyślnie autouzupełnianie miejsc wyświetla wszystkie typy miejsc, z tendencją do prognoz w pobliżu lokalizacji użytkownika, i pobiera wszystkie dostępne pola danych dla wybranego przez użytkownika miejsca. Ustaw opcje autouzupełniania miejsca, aby wyświetlać bardziej trafne prognozy, ograniczając lub modyfikując wyniki.
Ograniczenie wyników powoduje, że widżet autouzupełniania ignoruje wszystkie wyniki, które znajdują się poza obszarem ograniczenia. Często stosowaną praktyką jest ograniczenie wyników do granic mapy. W przypadku wyników z odchyleniem widżet autouzupełniania wyświetla wyniki w określonym obszarze, ale niektóre dopasowania mogą znajdować się poza tym obszarem.
Użyj właściwości origin
, aby określić punkt początkowy, od którego ma być obliczana odległość geodezyjna do miejsca docelowego. Jeśli ta wartość zostanie pominięta, odległość nie zostanie zwrócona.
Użyj właściwości includedPrimaryTypes
, aby określić maksymalnie 5 typów miejsc.
Jeśli nie określisz żadnych typów, zwracane będą miejsca wszystkich typów.
Pobieranie szczegółów miejsca
Aby zwrócić obiekt Place
z wyniku prognozy miejsca, najpierw wywołaj toPlace()
, a potem wywołaj fetchFields()
na wynikowym obiekcie Place
(identyfikator sesji z prognozy miejsca jest uwzględniany automatycznie). Naciśnięcie klawisza fetchFields()
kończy sesję autouzupełniania.
let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place. await place.fetchFields({ fields: ["displayName", "formattedAddress"], }); const placeInfo = document.getElementById("prediction"); placeInfo.textContent = "First predicted place: " + place.displayName + ": " + place.formattedAddress;
Tokeny sesji
Tokeny sesji grupują fazy zapytania i wyboru autouzupełniania wyszukiwania użytkownika w osobną sesję na potrzeby rozliczeń. Sesja rozpoczyna się, gdy użytkownik zaczyna pisać. Sesja kończy się, gdy użytkownik wybierze miejsce i wywoła wywołanie szczegółów miejsca.
Aby utworzyć nowy token sesji i dodać go do żądania, utwórz instancję AutocompleteSessionToken
, a następnie ustaw właściwość sessionToken
żądania, aby używać tokenów, jak pokazano w tym fragmencie kodu:
// Create a session token. const token = new AutocompleteSessionToken(); // Add the token to the request. // @ts-ignore request.sessionToken = token;
Sesja kończy się po wywołaniu funkcji fetchFields()
. Po utworzeniu instancji Place
nie musisz przekazywać tokena sesji do fetchFields()
, ponieważ jest to obsługiwane automatycznie.
await place.fetchFields({ fields: ["displayName", "formattedAddress"], });
Utwórz token sesji na potrzeby następnej sesji, tworząc nową instancję AutocompleteSessionToken
.
Rekomendacje dotyczące tokena sesji:
- Używaj tokenów sesji we wszystkich wywołaniach funkcji Autouzupełnianie miejsc.
- Generuj nowy token dla każdej sesji.
- W przypadku każdej nowej sesji przekaż unikalny token sesji. Używanie tego samego tokena w więcej niż 1 sesji spowoduje naliczenie opłaty za każde żądanie osobno.
Opcjonalnie możesz pominąć w żądaniu token sesji autouzupełniania. Jeśli token sesji zostanie pominięty, każde żądanie będzie rozliczane osobno, co spowoduje użycie kodu SKU Autocomplete – za żądanie. Jeśli ponownie użyjesz tokena sesji, sesja zostanie uznana za nieprawidłową, a żądania zostaną obciążone opłatą tak, jakby token sesji nie został podany.
Przykład
Gdy użytkownik wpisuje zapytanie, co kilka naciśnięć klawiszy (nie po każdym znaku) wysyłane jest żądanie autouzupełniania i zwracana jest lista możliwych wyników. Gdy użytkownik wybierze element z listy wyników, wybór ten jest traktowany jako żądanie, a wszystkie żądania wysłane podczas wyszukiwania są łączone i traktowane jako jedno żądanie. Jeśli użytkownik wybierze miejsce, zapytanie jest dostępne bezpłatnie, a opłata jest naliczana tylko za żądanie danych o miejscu. Jeśli użytkownik nie dokona wyboru w ciągu kilku minut od rozpoczęcia sesji, opłata zostanie naliczona tylko za zapytanie.
Z perspektywy aplikacji przepływ zdarzeń wygląda tak:
- Użytkownik zaczyna wpisywać zapytanie, aby wyszukać „Paryż, Francja”.
- Po wykryciu danych wejściowych użytkownika aplikacja tworzy nowy token sesji „Token A”.
- Gdy użytkownik wpisuje tekst, interfejs API co kilka znaków wysyła żądanie autouzupełniania i wyświetla nową listę potencjalnych wyników:
„P”
„Par”
„Paryż”
„Paryż, Fr”
- Gdy użytkownik dokona wyboru:
- Wszystkie żądania wynikające z zapytania są grupowane i dodawane do sesji reprezentowanej przez „Token A” jako jedno żądanie.
- Wybór użytkownika jest liczony jako żądanie szczegółów miejsca i dodawany do sesji reprezentowanej przez „Token A”.
- Sesja zostaje zakończona, a aplikacja odrzuca „Token A”.
Pełny przykładowy kod
Ta sekcja zawiera kompletne przykłady pokazujące, jak korzystać z interfejsu Place Autocomplete Data API .Podpowiedzi autouzupełniania miejsc
W tym przykładzie pokazujemy wywołanie funkcji fetchAutocompleteSuggestions()
dla danych wejściowych „Tadi”, a następnie wywołanie funkcji toPlace()
na pierwszym wyniku prognozy i wywołanie funkcji fetchFields()
w celu uzyskania szczegółów miejsca.
TypeScript
/** * Demonstrates making a single request for Place predictions, then requests Place Details for the first result. */ async function init() { // @ts-ignore const { Place, AutocompleteSessionToken, AutocompleteSuggestion } = await google.maps.importLibrary("places") as google.maps.PlacesLibrary; // Add an initial request body. let request = { input: "Tadi", locationRestriction: { west: -122.44, north: 37.8, east: -122.39, south: 37.78 }, origin: { lat: 37.7893, lng: -122.4039 }, includedPrimaryTypes: ["restaurant"], language: "en-US", region: "us", }; // Create a session token. const token = new AutocompleteSessionToken(); // Add the token to the request. // @ts-ignore request.sessionToken = token; // Fetch autocomplete suggestions. const { suggestions } = await AutocompleteSuggestion.fetchAutocompleteSuggestions(request); const title = document.getElementById('title') as HTMLElement; title.appendChild(document.createTextNode('Query predictions for "' + request.input + '":')); for (let suggestion of suggestions) { const placePrediction = suggestion.placePrediction; // Create a new list element. const listItem = document.createElement('li'); const resultsElement = document.getElementById("results") as HTMLElement; listItem.appendChild(document.createTextNode(placePrediction.text.toString())); resultsElement.appendChild(listItem); } let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place. await place.fetchFields({ fields: ['displayName', 'formattedAddress'], }); const placeInfo = document.getElementById("prediction") as HTMLElement; placeInfo.textContent = 'First predicted place: ' + place.displayName + ': ' + place.formattedAddress; } init();
JavaScript
/** * Demonstrates making a single request for Place predictions, then requests Place Details for the first result. */ async function init() { // @ts-ignore const { Place, AutocompleteSessionToken, AutocompleteSuggestion } = await google.maps.importLibrary("places"); // Add an initial request body. let request = { input: "Tadi", locationRestriction: { west: -122.44, north: 37.8, east: -122.39, south: 37.78, }, origin: { lat: 37.7893, lng: -122.4039 }, includedPrimaryTypes: ["restaurant"], language: "en-US", region: "us", }; // Create a session token. const token = new AutocompleteSessionToken(); // Add the token to the request. // @ts-ignore request.sessionToken = token; // Fetch autocomplete suggestions. const { suggestions } = await AutocompleteSuggestion.fetchAutocompleteSuggestions(request); const title = document.getElementById("title"); title.appendChild( document.createTextNode('Query predictions for "' + request.input + '":'), ); for (let suggestion of suggestions) { const placePrediction = suggestion.placePrediction; // Create a new list element. const listItem = document.createElement("li"); const resultsElement = document.getElementById("results"); listItem.appendChild( document.createTextNode(placePrediction.text.toString()), ); resultsElement.appendChild(listItem); } let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place. await place.fetchFields({ fields: ["displayName", "formattedAddress"], }); const placeInfo = document.getElementById("prediction"); placeInfo.textContent = "First predicted place: " + place.displayName + ": " + place.formattedAddress; } init();
CSS
/* * Always set the map height explicitly to define the size of the div element * that contains the map. */ #map { height: 100%; } /* * Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; }
HTML
<html> <head> <title>Place Autocomplete Data API Predictions</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <script type="module" src="./index.js"></script> </head> <body> <div id="title"></div> <ul id="results"></ul> <p><span id="prediction"></span></p> <img class="powered-by-google" src="https://storage.googleapis.com/geo-devrel-public-buckets/powered_by_google_on_white.png" alt="Powered by Google" /> <!-- prettier-ignore --> <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))}) ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "weekly"});</script> </body> </html>
Wypróbuj
Autouzupełnianie miejsc z sesjami
Ten przykład pokazuje te koncepcje:
- Wywoływanie
fetchAutocompleteSuggestions()
na podstawie zapytań użytkownika i wyświetlanie listy prognozowanych miejsc w odpowiedzi. - Używanie tokenów sesji do grupowania zapytania użytkownika z ostatecznym żądaniem szczegółów miejsca.
- Pobieranie szczegółów wybranego miejsca i wyświetlanie znacznika.
- Używanie umieszczania elementów sterujących do zagnieżdżania elementów interfejsu w elemencie
gmp-map
.
TypeScript
const mapElement = document.querySelector('gmp-map') as google.maps.MapElement; let innerMap: google.maps.Map; let marker: google.maps.marker.AdvancedMarkerElement; let titleElement = document.querySelector('.title') as HTMLElement; let resultsContainerElement = document.querySelector('.results') as HTMLElement; let inputElement = document.querySelector('input') as HTMLInputElement; let tokenStatusElement = document.querySelector('.token-status') as HTMLElement; let newestRequestId = 0; let tokenCount = 0; // Create an initial request body. const request: google.maps.places.AutocompleteRequest = { input: '', includedPrimaryTypes: [ 'restaurant', 'cafe', 'museum', 'park', 'botanical_garden', ], } async function init() { await google.maps.importLibrary('maps'); innerMap = mapElement.innerMap; innerMap.setOptions({ mapTypeControl: false, }); // Update request center and bounds when the map bounds change. google.maps.event.addListener(innerMap, 'bounds_changed', async () => { request.locationRestriction = innerMap.getBounds(); request.origin = innerMap.getCenter(); }); inputElement.addEventListener('input', makeAutocompleteRequest); } async function makeAutocompleteRequest(inputEvent) { // To avoid race conditions, store the request ID and compare after the request. const requestId = ++newestRequestId; const { AutocompleteSuggestion } = (await google.maps.importLibrary( 'places' )) as google.maps.PlacesLibrary; if (!inputEvent.target?.value) { titleElement.textContent = ''; resultsContainerElement.replaceChildren(); return; } // Add the latest char sequence to the request. request.input = (inputEvent.target as HTMLInputElement).value; // Fetch autocomplete suggestions and show them in a list. const { suggestions } = await AutocompleteSuggestion.fetchAutocompleteSuggestions(request); // If the request has been superseded by a newer request, do not render the output. if (requestId !== newestRequestId) return; titleElement.innerText = `Place predictions for "${request.input}"`; // Clear the list first. resultsContainerElement.replaceChildren(); for (const suggestion of suggestions) { const placePrediction = suggestion.placePrediction; if (!placePrediction) { continue; } // Create a link for the place, add an event handler to fetch the place. // We are using a button element to take advantage of its a11y capabilities. const placeButton = document.createElement('button'); placeButton.addEventListener('click', () => { onPlaceSelected(placePrediction.toPlace()); }); placeButton.textContent = placePrediction.text.toString(); placeButton.classList.add('place-button'); // Create a new list item element. const li = document.createElement('li'); li.appendChild(placeButton); resultsContainerElement.appendChild(li); } } // Event handler for clicking on a suggested place. async function onPlaceSelected(place: google.maps.places.Place) { const { AdvancedMarkerElement } = (await google.maps.importLibrary( 'marker' )) as google.maps.MarkerLibrary; await place.fetchFields({ fields: ['displayName', 'formattedAddress', 'location'], }); resultsContainerElement.textContent = `${place.displayName}: ${place.formattedAddress}`; titleElement.textContent = 'Selected Place:'; inputElement.value = ''; await refreshToken(); // Remove the previous marker, if it exists. if (marker) { marker.remove(); } // Create a new marker. marker = new AdvancedMarkerElement({ map: innerMap, position: place.location, title: place.displayName, }) // Center the map on the selected place. if (place.location) { innerMap.setCenter(place.location); innerMap.setZoom(15); } } // Helper function to refresh the session token. async function refreshToken() { const { AutocompleteSessionToken } = (await google.maps.importLibrary( 'places' )) as google.maps.PlacesLibrary; // Increment the token counter. tokenCount++; // Create a new session token and add it to the request. request.sessionToken = new AutocompleteSessionToken(); tokenStatusElement.textContent = `Session token count: ${tokenCount}`; } init();
JavaScript
const mapElement = document.querySelector('gmp-map'); let innerMap; let marker; let titleElement = document.querySelector('.title'); let resultsContainerElement = document.querySelector('.results'); let inputElement = document.querySelector('input'); let tokenStatusElement = document.querySelector('.token-status'); let newestRequestId = 0; let tokenCount = 0; // Create an initial request body. const request = { input: '', includedPrimaryTypes: [ 'restaurant', 'cafe', 'museum', 'park', 'botanical_garden', ], }; async function init() { await google.maps.importLibrary('maps'); innerMap = mapElement.innerMap; innerMap.setOptions({ mapTypeControl: false, }); // Update request center and bounds when the map bounds change. google.maps.event.addListener(innerMap, 'bounds_changed', async () => { request.locationRestriction = innerMap.getBounds(); request.origin = innerMap.getCenter(); }); inputElement.addEventListener('input', makeAutocompleteRequest); } async function makeAutocompleteRequest(inputEvent) { // To avoid race conditions, store the request ID and compare after the request. const requestId = ++newestRequestId; const { AutocompleteSuggestion } = (await google.maps.importLibrary('places')); if (!inputEvent.target?.value) { titleElement.textContent = ''; resultsContainerElement.replaceChildren(); return; } // Add the latest char sequence to the request. request.input = inputEvent.target.value; // Fetch autocomplete suggestions and show them in a list. const { suggestions } = await AutocompleteSuggestion.fetchAutocompleteSuggestions(request); // If the request has been superseded by a newer request, do not render the output. if (requestId !== newestRequestId) return; titleElement.innerText = `Place predictions for "${request.input}"`; // Clear the list first. resultsContainerElement.replaceChildren(); for (const suggestion of suggestions) { const placePrediction = suggestion.placePrediction; if (!placePrediction) { continue; } // Create a link for the place, add an event handler to fetch the place. // We are using a button element to take advantage of its a11y capabilities. const placeButton = document.createElement('button'); placeButton.addEventListener('click', () => { onPlaceSelected(placePrediction.toPlace()); }); placeButton.textContent = placePrediction.text.toString(); placeButton.classList.add('place-button'); // Create a new list item element. const li = document.createElement('li'); li.appendChild(placeButton); resultsContainerElement.appendChild(li); } } // Event handler for clicking on a suggested place. async function onPlaceSelected(place) { const { AdvancedMarkerElement } = (await google.maps.importLibrary('marker')); await place.fetchFields({ fields: ['displayName', 'formattedAddress', 'location'], }); resultsContainerElement.textContent = `${place.displayName}: ${place.formattedAddress}`; titleElement.textContent = 'Selected Place:'; inputElement.value = ''; await refreshToken(); // Remove the previous marker, if it exists. if (marker) { marker.remove(); } // Create a new marker. marker = new AdvancedMarkerElement({ map: innerMap, position: place.location, title: place.displayName, }); // Center the map on the selected place. if (place.location) { innerMap.setCenter(place.location); innerMap.setZoom(15); } } // Helper function to refresh the session token. async function refreshToken() { const { AutocompleteSessionToken } = (await google.maps.importLibrary('places')); // Increment the token counter. tokenCount++; // Create a new session token and add it to the request. request.sessionToken = new AutocompleteSessionToken(); tokenStatusElement.textContent = `Session token count: ${tokenCount}`; } init();
CSS
/* * Always set the map height explicitly to define the size of the div element * that contains the map. */ #map { height: 100%; } /* * Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } .place-button { height: 3rem; width: 100%; background-color: transparent; text-align: left; border: none; cursor: pointer; } .place-button:focus-visible { outline: 2px solid #0056b3; border-radius: 2px; } .input { width: 300px; font-size: small; margin-bottom: 1rem; } /* Styles for the floating panel */ .controls { background-color: #fff; border-radius: 8px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); font-family: sans-serif; font-size: small; margin: 12px; padding: 1rem; } .title { font-weight: bold; margin-top: 1rem; margin-bottom: 0.5rem; } .results { list-style-type: none; margin: 0; padding: 0; } .results li:not(:last-child) { border-bottom: 1px solid #ddd; } .results li:hover { background-color: #eee; }
HTML
<html> <head> <title>Place Autocomplete Data API Session</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <script type="module" src="./index.js"></script> <!-- prettier-ignore --> <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))}) ({key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "weekly"});</script> </head> <body> <gmp-map center="37.7893, -122.4039" zoom="12" map-id="DEMO_MAP_ID"> <div class="controls" slot="control-inline-start-block-start" > <input type="text" class="input" placeholder="Search for a place..." autocomplete="off" /><!-- Turn off the input's own autocomplete (not supported by all browsers).--> <div class="token-status"></div> <div class="title"></div> <ol class="results"></ol> </div> </gmp-map> </body> </html>