واجهة برمجة التطبيقات الخاصة بميزة "الإكمال التلقائي للأماكن"

تتيح لك واجهة برمجة التطبيقات Place Autocomplete Data API جلب الاقتراحات المتعلّقة بالأماكن آليًا، لإنشاء تجارب إكمال تلقائي مخصّصة بدرجة تحكّم أدق مما هو ممكن باستخدام التطبيق المصغّر للإكمال التلقائي. في هذا الدليل، ستتعرّف على كيفية استخدام واجهة برمجة التطبيقات Place Autocomplete 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 لتحديد ما يصل إلى خمسة أنواع أماكن. في حال عدم تحديد أي أنواع، سيتم عرض أماكن من جميع الأنواع.

الاطّلاع على مرجع واجهة برمجة التطبيقات

الحصول على تفاصيل المكان

لعرض عنصر 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. عند رصد إدخال المستخدم، ينشئ التطبيق رمزًا مميّزًا جديدًا لجلسة ، وهو "الرمز المميّز (أ)".
  3. أثناء كتابة المستخدم، تُرسل واجهة برمجة التطبيقات طلبًا للإكمال التلقائي بعد كل بضع أحرف، وتعرض قائمة جديدة بالنتائج المحتملة لكل منها:
    "P"
    "Par"
    "Paris,"
    "Paris, Fr"
  4. عندما يختار المستخدم أحد الخيارات:
    • يتم تجميع جميع الطلبات الناتجة عن طلب البحث وإضافتها إلى الجلسة التي يمثّلها "الرمز المميّز (أ)"، كطلب واحد.
    • يتم احتساب اختيار المستخدم كطلب لتفاصيل مكان، ويتمّ إضافته إلى الجلسة التي يمثّلها "الرمز المميّز (أ)".
  5. تنتهي الجلسة، ويتخلّص التطبيق من "الرمز المميّز أ".
مزيد من المعلومات عن كيفية فوترة الجلسات

مثال كامل على الرمز البرمجي

يحتوي هذا القسم على أمثلة كاملة توضّح كيفية استخدام واجهة برمجة التطبيقات Place Autocomplete 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>

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

تجربة عيّنة