API של נתוני השלמה אוטומטית למקומות

Place השלמה אוטומטית Data API של מאפשר לך לאחזר חיזויים של מקומות באופן פרוגרמטי, כדי ליצור חוויות מותאמות אישית של השלמה אוטומטית עם רמת שליטה גבוהה יותר מזו של הווידג'ט של ההשלמה האוטומטית. במדריך הזה תלמדו איך להשתמש ב-Place השלמה אוטומטית Data API כדי לשלוח בקשות להשלמה אוטומטית על סמך שאילתות משתמשים.

הדוגמה הבאה מציגה שילוב פשוט מסוג 'מקדמה'. מזינים את שאילתת החיפוש ולוחצים על כדי לבחור את התוצאה הרצויה.

השלמה אוטומטית של בקשות

בקשה להשלמה אוטומטית מקבלת מחרוזת קלט של שאילתה ומחזירה רשימה של חיזויים של מקומות. כדי לבצע בקשה להשלמה אוטומטית, צריך להתקשר למספר fetchAutocompleteSuggestions() ולהעביר בקשה עם המאפיינים הנדרשים. המאפיין input מכיל את המחרוזת לחיפוש. באפליקציה אופיינית, הערך הזה מתעדכן בכל פעם שהמשתמש מקליד שאילתה. הבקשה צריכה לכלול sessionToken, שישמש למטרות חיוב.

קטע הקוד הבא מציג יצירה של גוף בקשה והוספת אסימון סשן, ולאחר מכן קריאה ל-fetchAutocompleteSuggestions() כדי לקבל רשימה של פריטי 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;

הגבלת חיזויים של השלמה אוטומטית

כברירת מחדל, התכונה'השלמה אוטומטית של מקומות' מציגה את כל סוגי המקומות, ללא חיזוי לחיזויים שנמצאים בקרבת המיקום של המשתמש, ומאחזרת את כל שדות הנתונים הזמינים לגבי המקום שהמשתמש בוחר. הגדר אפשרויות של השלמה אוטומטית של מקומות כדי להציג חיזויים רלוונטיים יותר, על ידי הגבלת התוצאות או הטייה שלהן.

הגבלת התוצאות גורמת לווידג'ט ההשלמה האוטומטית להתעלם מתוצאות שלא נמצאות בתחום ההגבלה. שיטה נפוצה היא להגביל את התוצאות לגבולות המפה. תוצאות הטייה גורמים לווידג'ט ההשלמה האוטומטית להציג תוצאות בתוך האזור שצוין, אך ייתכן שהתאמות מסוימות יהיו מחוץ לאזור הזה.

המאפיין origin משמש לציון נקודת המוצא שממנה יש לחשב את המרחק הגאודזי ליעד. אם לא תציינו ערך, המרחק לא יוחזר.

אפשר להשתמש במאפיין includedPrimaryTypes כדי לציין עד חמישה סוגי מקומות. אם לא מציינים סוגים, מקומות מכל הסוגים יוחזרו.

הפניית ה-API

קבלת פרטים על המקום

כדי להחזיר אובייקט Place מתוצאה של חיזוי מקום, קודם צריך להפעיל את toPlace(), ולאחר מכן להפעיל את fetchFields() באובייקט Place שמתקבל (מזהה הסשן מהחיזוי של המקום נכלל באופן אוטומטי). קריאה ל-fetchFields() תסגור את הסשן של ההשלמה האוטומטית.

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;

אסימוני סשן

אסימונים של סשן מקבצים את שלבי השאילתה והבחירה של החיפוש של המשתמש בהשלמה אוטומטית של סשן נפרד, למטרות חיוב. הסשן מתחיל כשהמשתמש מתחיל להקליד. הסשן מסתיים כאשר המשתמש בוחר מקום ומתבצעת קריאה לפרטי המקום.

כדי ליצור אסימון חדש של סשן ולהוסיף אותו לבקשה, צריך ליצור מופע של AutocompleteSessionToken, ואז להגדיר את המאפיין sessionToken של הבקשה לשימוש באסימונים, כפי שמוצג בקטע הקוד הבא:

// Create a session token.
const token = new AutocompleteSessionToken();

// Add the token to the request.
// @ts-ignore
request.sessionToken = token;

סשן מסתיים כאשר מתבצעת קריאה ל-fetchFields(). אחרי יצירת המכונה של Place, אין צורך להעביר את אסימון הסשן ל-fetchFields() כי הפעולה הזו מטופלת באופן אוטומטי.

await place.fetchFields({
  fields: ["displayName", "formattedAddress"],
});
await place.fetchFields({
    fields: ['displayName'],
  });

כדי ליצור אסימון סשן לסשן הבא, צריך ליצור מופע חדש של AutocompleteSessionToken.

המלצות לאסימוני סשן:

  • יש להשתמש באסימוני סשן לכל הקריאות להשלמה אוטומטית של מקומות.
  • יצירת אסימון חדש לכל סשן.
  • מעבירים אסימון סשן ייחודי לכל סשן חדש. שימוש באותו אסימון עבור יותר מסשן אחד יגרום לחיוב כל בקשה בנפרד.

אפשר להשמיט בבקשה את אסימון הסשן של ההשלמה האוטומטית. אם אסימון הסשן יושמט, החיוב עבור כל בקשה מתבצע בנפרד, והמק"ט יופעל על ידי השלמה אוטומטית – לכל בקשה. במקרה של שימוש חוזר באסימון סשן, הסשן נחשב לא חוקי והבקשות מחויבות כאילו לא סופק אסימון סשן.

דוגמה

כשהמשתמש מקליד שאילתה, מתבצעת בקשה להשלמה אוטומטית כל כמה הקשות על מקשים (לא לכל תו), ומוחזרת רשימה של תוצאות אפשריות. כשמשתמש מבצע בחירה מרשימת התוצאות, הבחירה נספרת כבקשה, וכל הבקשות שבוצעו במהלך החיפוש מקובצות ונספרות כבקשה יחידה. אם המשתמש יבחר מקום, שאילתת החיפוש תהיה זמינה ללא תשלום ורק הבקשה לנתוני מקום תחויב. אם המשתמש לא מבצע בחירה תוך מספר דקות מתחילת הסשן, רק שאילתת החיפוש תחויב.

מבחינת אפליקציה, רצף האירועים נראה כך:

  1. משתמש מתחיל להקליד שאילתה כדי לחפש "פריז, צרפת".
  2. האפליקציה מזהה קלט של משתמש ויוצרת אסימון סשן חדש – אסימון A.
  3. בזמן שהמשתמש מקליד, ה-API שולח בקשה להשלמה אוטומטית כל כמה תווים, ומציג רשימה חדשה של תוצאות פוטנציאליות לכל אחד מהם:
    "P"
    "Par"
    "Paris",
    "Paris, Fr"
  4. כשהמשתמש מבצע בחירה:
    • כל הבקשות שנובעות מהשאילתה מקובצות ומתווספות לסשן שמיוצג על ידי אסימון A, כבקשה יחידה.
    • הבחירה של המשתמש נספרת כבקשה של פרטי מקום, והיא מתווספת לסשן שמיוצג על ידי "אסימון A".
  5. הסשן הסתיים, והאפליקציה 'אסימון A' נמחקת.
מידע על אופן החיוב על ביקורים

השלמת קוד לדוגמה

קטע זה מכיל דוגמאות מלאות שממחישות כיצד להשתמש ב-Place השלמה אוטומטית Data API .

חיזויים של השלמה אוטומטית של מקומות

בדוגמה הבאה מוצגת קריאה ל- fetchAutocompleteSuggestions() בתור הקלט "Tadi", ולאחר מכן קריאה ל-toPlace() בתוצאת החיזוי הראשונה, ולאחר מכן קריאה ל-fetchFields() לקבלת פרטי המקום.

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>

רוצה לנסות את הדוגמה

קידום הקלדה של ההשלמה האוטומטית בסשנים

בדוגמה הזו מוצגת קריאה ל-fetchAutocompleteSuggestions() על סמך שאילתות של משתמשים, הצגת רשימה של מקומות צפויים בתגובה ולבסוף אחזור פרטי המקום של המקום שנבחר. הדוגמה גם ממחישה את השימוש באסימוני סשן כדי לקבץ שאילתת משתמש עם הבקשה הסופית של פרטי המקום.

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>

רוצה לנסות את הדוגמה