API Dữ liệu tự động hoàn thành địa điểm cho phép bạn tìm nạp thông tin dự đoán về địa điểm theo phương thức lập trình để tạo trải nghiệm tự động hoàn thành tuỳ chỉnh với mức độ kiểm soát chi tiết hơn so với tiện ích tự động hoàn thành. Trong hướng dẫn này, bạn sẽ tìm hiểu cách sử dụng API Dữ liệu tự động hoàn thành địa điểm để tạo các yêu cầu tự động hoàn thành dựa trên truy vấn của người dùng.
Ví dụ sau đây cho thấy cách tích hợp tính năng nhập trước đơn giản. Nhập cụm từ tìm kiếm, sau đó nhấp vào biểu tượng để chọn kết quả bạn muốn.
Yêu cầu tự động hoàn thành
Yêu cầu tự động hoàn thành sẽ lấy một chuỗi đầu vào truy vấn và trả về danh sách các địa điểm được dự đoán. Để tạo yêu cầu tự động hoàn thành, hãy gọi fetchAutocompleteSuggestions()
và truyền yêu cầu có các thuộc tính cần thiết. Thuộc tính input
chứa chuỗi cần tìm kiếm; trong một ứng dụng thông thường, giá trị này sẽ được cập nhật khi người dùng nhập một truy vấn. Yêu cầu phải bao gồm sessionToken
, được dùng cho mục đích thanh toán.
Đoạn mã sau đây cho thấy cách tạo nội dung yêu cầu và thêm mã thông báo phiên, sau đó gọi fetchAutocompleteSuggestions()
để lấy danh sách 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;
Hạn chế cụm từ gợi ý của tính năng Tự động hoàn thành
Theo mặc định, tính năng Tự động hoàn thành địa điểm sẽ hiển thị tất cả các loại địa điểm, ưu tiên các địa điểm dự đoán gần vị trí của người dùng và tìm nạp tất cả các trường dữ liệu có sẵn cho địa điểm mà người dùng đã chọn. Đặt các tuỳ chọn Tự động hoàn thành cho Địa điểm để hiển thị các nội dung dự đoán phù hợp hơn bằng cách hạn chế hoặc thiên vị kết quả.
Việc hạn chế kết quả sẽ khiến tiện ích Tự động hoàn thành bỏ qua mọi kết quả nằm ngoài khu vực hạn chế. Một phương pháp phổ biến là hạn chế kết quả trong phạm vi bản đồ. Việc thiên vị kết quả sẽ khiến tiện ích Tự động hoàn thành hiển thị kết quả trong khu vực đã chỉ định, nhưng một số kết quả trùng khớp có thể nằm ngoài khu vực đó.
Sử dụng thuộc tính origin
để chỉ định điểm gốc để tính toán khoảng cách trắc địa đến đích. Nếu bạn bỏ qua giá trị này, thì hệ thống sẽ không trả về khoảng cách.
Sử dụng thuộc tính includedPrimaryTypes
để chỉ định tối đa 5 loại địa điểm.
Nếu bạn không chỉ định loại nào, thì hệ thống sẽ trả về địa điểm thuộc mọi loại.
Nhận thông tin chi tiết về địa điểm
Để trả về đối tượng Place
từ kết quả dự đoán địa điểm, trước tiên, hãy gọi toPlace()
, sau đó gọi fetchFields()
trên đối tượng Place
thu được (mã phiên từ kết quả dự đoán địa điểm sẽ tự động được đưa vào). Việc gọi fetchFields()
sẽ kết thúc phiên tự động hoàn thành.
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;
Mã thông báo phiên
Mã thông báo phiên nhóm các giai đoạn truy vấn và lựa chọn của một lượt tìm kiếm tự động hoàn thành của người dùng thành một phiên riêng biệt cho mục đích thanh toán. Phiên hoạt động bắt đầu khi người dùng bắt đầu nhập. Phiên kết thúc khi người dùng chọn một địa điểm và thực hiện lệnh gọi đến Thông tin chi tiết về địa điểm.
Để tạo mã thông báo phiên mới và thêm mã thông báo đó vào một yêu cầu, hãy tạo một thực thể của AutocompleteSessionToken
, sau đó đặt thuộc tính sessionToken
của yêu cầu để sử dụng mã thông báo như trong đoạn mã sau:
// Create a session token. const token = new AutocompleteSessionToken(); // Add the token to the request. // @ts-ignore request.sessionToken = token;
Một phiên sẽ kết thúc khi fetchFields()
được gọi. Sau khi tạo thực thể Place
, bạn không cần truyền mã thông báo phiên vào fetchFields()
vì mã này sẽ được xử lý tự động.
await place.fetchFields({ fields: ["displayName", "formattedAddress"], });
await place.fetchFields({ fields: ['displayName'], });
Tạo mã thông báo phiên cho phiên tiếp theo bằng cách tạo một thực thể mới của AutocompleteSessionToken
.
Đề xuất về mã thông báo phiên:
- Sử dụng mã thông báo phiên cho tất cả lệnh gọi Tự động hoàn thành địa điểm.
- Tạo mã thông báo mới cho mỗi phiên.
- Truyền mã thông báo phiên duy nhất cho mỗi phiên mới. Việc sử dụng cùng một mã thông báo cho nhiều phiên sẽ khiến mỗi yêu cầu được tính phí riêng lẻ.
Bạn có thể tuỳ ý bỏ qua mã thông báo phiên tự động hoàn thành khỏi một yêu cầu. Nếu bạn bỏ qua mã thông báo phiên, thì mỗi yêu cầu sẽ được tính phí riêng, kích hoạt SKU Tự động hoàn thành – Theo yêu cầu. Nếu bạn sử dụng lại mã thông báo phiên, thì phiên đó sẽ được coi là không hợp lệ và các yêu cầu sẽ bị tính phí như thể không có mã thông báo phiên nào được cung cấp.
Ví dụ:
Khi người dùng nhập một truy vấn, một yêu cầu tự động hoàn thành sẽ được gọi sau mỗi vài thao tác nhấn phím (không phải theo từng ký tự) và danh sách kết quả có thể có sẽ được trả về. Khi người dùng chọn một mục trong danh sách kết quả, mục đó được tính là một yêu cầu và tất cả các yêu cầu được thực hiện trong quá trình tìm kiếm sẽ được gộp lại và tính là một yêu cầu. Nếu người dùng chọn một địa điểm, thì cụm từ tìm kiếm sẽ được cung cấp miễn phí và chỉ yêu cầu Dữ liệu địa điểm mới bị tính phí. Nếu người dùng không đưa ra lựa chọn trong vòng vài phút kể từ khi bắt đầu phiên, thì chỉ truy vấn tìm kiếm mới bị tính phí.
Từ quan điểm của một ứng dụng, luồng sự kiện diễn ra như sau:
- Người dùng bắt đầu nhập cụm từ tìm kiếm "Paris, Pháp".
- Khi phát hiện hoạt động đầu vào của người dùng, ứng dụng sẽ tạo một mã thông báo phiên mới, "Mã thông báo A".
- Khi người dùng nhập, API sẽ tạo một yêu cầu tự động hoàn thành sau mỗi vài ký tự, hiển thị một danh sách mới gồm các kết quả tiềm năng cho mỗi ký tự:
"P"
"Par"
"Paris,"
"Paris, Fr"
- Khi người dùng chọn:
- Tất cả các yêu cầu phát sinh từ truy vấn này được nhóm lại và thêm vào phiên được biểu thị bằng "Mã thông báo A", dưới dạng một yêu cầu duy nhất.
- Lựa chọn của người dùng được tính là một yêu cầu Thông tin chi tiết về địa điểm và được thêm vào phiên được biểu thị bằng "Mã thông báo A".
- Phiên kết thúc và ứng dụng sẽ loại bỏ "Mã thông báo A".
Mã ví dụ hoàn chỉnh
Phần này chứa các ví dụ hoàn chỉnh cho thấy cách sử dụng API Dữ liệu tự động hoàn thành địa điểm .Đặt cụm từ gợi ý của tính năng tự động hoàn thành
Ví dụ sau đây minh hoạ cách gọi fetchAutocompleteSuggestions()
cho dữ liệu đầu vào "Tadi", sau đó gọi toPlace()
trên kết quả dự đoán đầu tiên, theo sau là lệnh gọi đến fetchFields()
để lấy thông tin chi tiết về địa điểm.
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>
Thử mẫu
Đặt tính năng tự động hoàn thành trước bằng phiên
Ví dụ này minh hoạ cách gọi fetchAutocompleteSuggestions()
dựa trên cụm từ tìm kiếm của người dùng, hiển thị danh sách các địa điểm được dự đoán để phản hồi và cuối cùng truy xuất thông tin chi tiết về địa điểm cho địa điểm đã chọn. Ví dụ này cũng minh hoạ cách sử dụng mã thông báo phiên để nhóm một truy vấn của người dùng với yêu cầu Thông tin chi tiết về địa điểm cuối cùng.
TypeScript
let title; let results; let input; let token; // Add an initial request body. let request = { input: "", 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", }; async function init() { token = new google.maps.places.AutocompleteSessionToken(); title = document.getElementById('title'); results = document.getElementById('results'); input = document.querySelector("input"); input.addEventListener("input", makeAcRequest); request = refreshToken(request) as any; } async function makeAcRequest(input) { // Reset elements and exit if an empty string is received. if (input.target.value == '') { title.innerText = ''; results.replaceChildren(); return; } // Add the latest char sequence to the request. request.input = input.target.value; // Fetch autocomplete suggestions and show them in a list. // @ts-ignore const { suggestions } = await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request); title.innerText = 'Query predictions for "' + request.input + '"'; // Clear the list first. results.replaceChildren(); for (const suggestion of suggestions) { const placePrediction = suggestion.placePrediction; // Create a link for the place, add an event handler to fetch the place. const a = document.createElement('a'); a.addEventListener('click', () => { onPlaceSelected(placePrediction!.toPlace()); }); a.innerText = placePrediction!.text.toString(); // Create a new list element. const li = document.createElement('li'); li.appendChild(a); results.appendChild(li); } } // Event handler for clicking on a suggested place. async function onPlaceSelected(place) { await place.fetchFields({ fields: ['displayName', 'formattedAddress'], }); let placeText = document.createTextNode(place.displayName + ': ' + place.formattedAddress); results.replaceChildren(placeText); title.innerText = 'Selected Place:'; input.value = ''; refreshToken(request); } // Helper function to refresh the session token. async function refreshToken(request) { // Create a new session token and add it to the request. token = new google.maps.places.AutocompleteSessionToken(); request.sessionToken = token; return request; } declare global { interface Window { init: () => void; } } window.init = init;
JavaScript
let title; let results; let input; let token; // Add an initial request body. let request = { input: "", 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", }; async function init() { token = new google.maps.places.AutocompleteSessionToken(); title = document.getElementById("title"); results = document.getElementById("results"); input = document.querySelector("input"); input.addEventListener("input", makeAcRequest); request = refreshToken(request); } async function makeAcRequest(input) { // Reset elements and exit if an empty string is received. if (input.target.value == "") { title.innerText = ""; results.replaceChildren(); return; } // Add the latest char sequence to the request. request.input = input.target.value; // Fetch autocomplete suggestions and show them in a list. // @ts-ignore const { suggestions } = await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions( request, ); title.innerText = 'Query predictions for "' + request.input + '"'; // Clear the list first. results.replaceChildren(); for (const suggestion of suggestions) { const placePrediction = suggestion.placePrediction; // Create a link for the place, add an event handler to fetch the place. const a = document.createElement("a"); a.addEventListener("click", () => { onPlaceSelected(placePrediction.toPlace()); }); a.innerText = placePrediction.text.toString(); // Create a new list element. const li = document.createElement("li"); li.appendChild(a); results.appendChild(li); } } // Event handler for clicking on a suggested place. async function onPlaceSelected(place) { await place.fetchFields({ fields: ["displayName", "formattedAddress"], }); let placeText = document.createTextNode( place.displayName + ": " + place.formattedAddress, ); results.replaceChildren(placeText); title.innerText = "Selected Place:"; input.value = ""; refreshToken(request); } // Helper function to refresh the session token. async function refreshToken(request) { // Create a new session token and add it to the request. token = new google.maps.places.AutocompleteSessionToken(); request.sessionToken = token; return request; } window.init = 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; } a { cursor: pointer; text-decoration: underline; color: blue; } input { width: 300px; }
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> </head> <body> <input id="input" type="text" placeholder="Search for a place..." /> <div id="title"></div> <ul id="results"></ul> <img class="powered-by-google" src="https://storage.googleapis.com/geo-devrel-public-buckets/powered_by_google_on_white.png" alt="Powered by Google" /> <!-- The `defer` attribute causes the script to execute after the full HTML document has been parsed. For non-blocking uses, avoiding race conditions, and consistent behavior across browsers, consider loading using Promises. See https://developers.google.com/maps/documentation/javascript/load-maps-js-api for more information. --> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=init&libraries=places&v=weekly" defer ></script> </body> </html>