API dữ liệu tự động hoàn thành địa điểm

API dữ liệu tự động hoàn thành địa điểm cho phép bạn tìm nạp các thông tin dự đoán địa điểm theo phương thức lập trình, để tạo ra trải nghiệm tự động hoàn thành tuỳ chỉnh ở mức độ kiểm soát tố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 của địa điểm để đưa ra 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 một quá trình tích hợp nhập trước đơn giản. Nhập cụm từ tìm kiếm rồi nhấp để 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ẽ nhận một chuỗi nhập truy vấn và trả về danh sách các dự đoán địa điểm. Để 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, dùng cho mục đích thanh toán.

Đoạn mã sau đây cho thấy việc tạo nội dung yêu cầu và thêm mã 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;

Ràng buộc trong các 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 hiển thị tất cả các loại địa điểm, thiên về các cụm từ gợi ý 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 tùy chọn Tự động hoàn thành địa điểm để đưa ra các dự đoán phù hợp hơn bằng cách hạn chế hoặc xu hướng kết quả.

Khi bạn hạn chế kết quả, tiện ích Tự động hoàn thành sẽ bỏ qua mọi kết quả nằm ngoài vùng hạn chế. Một phương pháp phổ biến là giới hạn kết quả ở các ranh giới bản đồ. Kết quả xu hướng giúp tiện ích Tự động hoàn thành hiển thị kết quả trong khu vực được chỉ định, nhưng một số kết quả phù hợ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 khoảng cách trắc địa đến điểm đến. Nếu giá trị này bị bỏ qua, hàm 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, hàm sẽ trả về các địa điểm thuộc tất cả các loại.

Xem tài liệu tham khảo API

Xem thông tin chi tiết về địa điểm

Để trả về một đối tượng Place qua 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 hoạt động từ thông tin dự đoán địa điểm sẽ tự động được bao gồm). 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 sẽ nhóm các giai đoạn truy vấn và lựa chọn của nội dung 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 truy cập kết thúc khi người dùng chọn một địa điểm và thực hiện cuộc 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ã đó vào yêu cầu, hãy tạo một bản sao của AutocompleteSessionToken, sau đó đặt thuộc tính sessionToken của yêu cầu để sử dụng mã như minh hoạ 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 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 đến 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ã 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ã phiên cho tất cả các lệnh gọi Tự động hoàn thành địa điểm.
  • Tạo một mã thông báo mới cho mỗi phiên.
  • Truyền một 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 bị tính phí riêng.

Bạn có thể tuỳ ý bỏ qua mã thông báo phiên tự động hoàn thành khỏi yêu cầu. Nếu mã phiên hoạt động bị bỏ qua, 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ẽ bị coi là không hợp lệ và các yêu cầu sẽ bị tính phí như khi bạn không cung cấp mã thông báo phiên nào.

Ví dụ:

Khi người dùng nhập truy vấn, một yêu cầu tự động hoàn thành sẽ được gọi sau mỗi vài lần nhấn phím (không phải mỗi ký tự) và một danh sách kết quả có thể có sẽ được trả về. Khi người dùng lựa chọn trong danh sách kết quả, lựa chọn đó sẽ được tính là một yêu cầu và tất cả các yêu cầu đưa ra trong quá trình tìm kiếm sẽ được nhóm lại và được tính là một yêu cầu duy nhất. Nếu người dùng chọn một địa điểm, thì cụm từ tìm kiếm đó sẽ không mất phí và chỉ tính phí cho yêu cầu dữ liệu về Địa điểm. Nếu người dùng không lựa chọn trong vòng vài phút đầu phiên, thì hệ thống chỉ tính phí cụm từ tìm kiếm.

Từ góc độ của một ứng dụng, luồng sự kiện sẽ diễn ra như sau:

  1. Một người dùng bắt đầu nhập cụm từ để tìm kiếm "Paris, France".
  2. 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 có tên "Token A".
  3. Khi người dùng nhập, cứ sau vài ký tự, API sẽ đưa ra một yêu cầu tự động hoàn thành cho mỗi nội dung:
    "P"
    "Par"
    "Paris",
    "Paris, Fr"
  4. Khi người dùng đưa ra lựa chọn:
    • Tất cả các yêu cầu đến từ truy vấn đều đượ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 Chi tiết địa điểm và được thêm vào phiên được biểu thị bằng "Mã thông báo A".
  5. Phiên này kết thúc và ứng dụng sẽ loại bỏ "Token A" (Mã thông báo A).
Tìm hiểu về cách tính phí phiên hoạt động

Hoàn tất đoạn mã ví dụ

Phần này chứa các ví dụ hoàn chỉnh minh hoạ cách sử dụng API dữ liệu tự động hoàn thành đối với địa điểm .

Các cụm từ gợi ý của tính năng tự động hoàn thành địa điểm

Ví dụ sau minh hoạ việc 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, tiếp theo là lệnh gọi đến fetchFields() để xem 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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 các 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 sẽ được phản hồi và cuối cùng là 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ạ việc sử dụng mã phiên hoạt động để 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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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>

Thử mẫu