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

ממשק ה-API להשלמה אוטומטית של Place מאפשר לאחזר חיזויים לגבי מקומות באופן פרוגרמטי כדי ליצור חוויית השלמה אוטומטית מותאמת אישית עם רמה גבוהה יותר של שליטה בהשוואה לווידג'ט של ההשלמה האוטומטית. במדריך הזה מוסבר איך להשתמש ב-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.

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

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

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

דוגמה

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

מנקודת מבט של אפליקציה, זרימת האירועים מתנהלת כך:

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

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

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

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

הדוגמה הבאה כוללת הפעלה של 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>

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

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

כדאי לנסות דוגמה