تتيح لك واجهة برمجة التطبيقات 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;
تقييد عبارات البحث المقترَحة من ميزة "الإكمال التلقائي"
تعرض خدمة "الإكمال التلقائي للأماكن" تلقائيًا جميع أنواع الأماكن، مع إعطاء الأولوية للتوقّعات القريبة من الموقع الجغرافي للمستخدم، وتستردّ جميع حقول البيانات المتاحة للمكان الذي اختاره المستخدم. اضبط خيارات الإكمال التلقائي الخاصة بخدمة Place لتقديم توقّعات أكثر صلة بالموضوع، وذلك عن طريق تقييد النتائج أو تحسينها.
يؤدي حصر النتائج إلى تجاهل أداة الإكمال التلقائي لأي نتائج خارج منطقة الحصر. من الممارسات الشائعة حصر النتائج في حدود الخريطة. يؤدي تحيز النتائج إلى عرض أداة الإكمال التلقائي لنتائج ضمن المنطقة المحدّدة، ولكن قد تكون بعض النتائج المطابقة خارج هذه المنطقة.
استخدِم السمة 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;
رموز الجلسات المميزة
تجمع رموز الجلسات بين مرحلتَي طلب البحث والاختيار في عملية بحث الإكمال التلقائي التي يجريها المستخدم، وذلك في جلسة منفصلة لأغراض الفوترة. تبدأ الجلسة عندما يبدأ المستخدم في الكتابة. تنتهي الجلسة عندما يختار المستخدم مكانًا ويتم إجراء طلب إلى Place Details.
لإنشاء رمز مميّز جديد للجلسة وإضافته إلى طلب، أنشئ مثيلاً من
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"], });
أنشئ رمزًا مميزًا للجلسة التالية من خلال إنشاء مثيل جديد من AutocompleteSessionToken
.
اقتراحات الرموز المميزة للجلسة:
- استخدِم الرموز المميّزة للجلسات في جميع طلبات Place Autocomplete.
- إنشاء رمز مميّز جديد لكل جلسة
- مرِّر رمزًا مميزًا فريدًا للجلسة لكل جلسة جديدة. سيؤدي استخدام الرمز المميز نفسه لأكثر من جلسة واحدة إلى تحصيل رسوم من كل طلب على حدة.
يمكنك اختياريًا حذف رمز الجلسة الخاص بميزة الإكمال التلقائي من الطلب. في حال عدم تضمين رمز الجلسة، يتم تحصيل رسوم كل طلب على حدة، ما يؤدي إلى تفعيل وحدة حفظ المخزون الإكمال التلقائي - لكل طلب. في حال إعادة استخدام رمز مميز للجلسة، تُعدّ الجلسة غير صالحة ويتم تحصيل رسوم مقابل الطلبات كما لو لم يتم تقديم رمز مميز للجلسة.
مثال
أثناء كتابة المستخدم لطلب بحث، يتم استدعاء طلب إكمال تلقائي كل بضع ضغطات على المفاتيح (وليس لكل حرف)، ويتم عرض قائمة بالنتائج المحتملة. عندما يختار المستخدم نتيجة من قائمة النتائج، يتم احتساب هذا الاختيار كطلب، ويتم تجميع كل الطلبات التي تم إجراؤها أثناء البحث واحتسابها كطلب واحد. إذا اختار المستخدم مكانًا، سيكون طلب البحث متاحًا بدون أي رسوم، وسيتم تحصيل رسوم طلب بيانات المكان فقط. إذا لم يحدّد المستخدم أي خيار خلال بضع دقائق من بداية الجلسة، سيتم تحصيل رسوم مقابل طلب البحث فقط.
من منظور التطبيق، يكون تسلسل الأحداث على النحو التالي:
- يبدأ المستخدم في كتابة طلب بحث للعثور على "باريس، فرنسا".
- عند رصد إدخال من المستخدم، ينشئ التطبيق رمزًا مميزًا جديدًا للجلسة، وهو "الرمز المميز أ".
- أثناء كتابة المستخدم، ترسل واجهة برمجة التطبيقات طلب إكمال تلقائي كل بضعة أحرف، وتعرض قائمة جديدة بالنتائج المحتملة لكل طلب:
"ب"
"بر"
"برلين"
"برلين، ألمانيا"
- عندما يحدّد المستخدم خيارًا:
- يتم تجميع جميع الطلبات الناتجة عن طلب البحث وإضافتها إلى الجلسة الممثّلة بالرمز المميّز "أ"، وذلك كطلب واحد.
- يتم احتساب اختيار المستخدِم كطلب تفاصيل مكان، ويتم إضافته إلى الجلسة الممثّلة بالرمز المميز "الرمز المميز أ".
- تنتهي الجلسة، ويتجاهل التطبيق الرمز المميّز "أ".
مثال كامل على الرمز البرمجي
يحتوي هذا القسم على أمثلة كاملة توضّح كيفية استخدام 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 titleElement; let resultsContainerElement; let inputElement; let newestRequestId = 0; // Add an initial request body. const 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', }; function init() { titleElement = document.getElementById('title'); resultsContainerElement = document.getElementById('results'); inputElement = document.querySelector('input'); inputElement.addEventListener('input', makeAutocompleteRequest); refreshToken(request); } async function makeAutocompleteRequest(inputEvent) { // Reset elements and exit if an empty string is received. if (inputEvent.target.value == '') { titleElement.innerText = ''; resultsContainerElement.replaceChildren(); return; } // Add the latest char sequence to the request. request.input = inputEvent.target.value; // To avoid race conditions, store the request ID and compare after the request. const requestId = ++newestRequestId; // Fetch autocomplete suggestions and show them in a list. // @ts-ignore const { suggestions } = await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request); // If the request has been superseded by a newer request, do not render the output. if (requestId !== newestRequestId) return; titleElement.innerText = `Query predictions for "${request.input}"`; // Clear the list first. resultsContainerElement.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 item element. const li = document.createElement('li'); li.appendChild(a); resultsContainerElement.appendChild(li); } } // Event handler for clicking on a suggested place. async function onPlaceSelected(place) { await place.fetchFields({ fields: ['displayName', 'formattedAddress'], }); const placeText = document.createTextNode(`${place.displayName}: ${place.formattedAddress}`); resultsContainerElement.replaceChildren(placeText); titleElement.innerText = 'Selected Place:'; inputElement.value = ''; refreshToken(request); } // Helper function to refresh the session token. function refreshToken(request) { // Create a new session token and add it to the request. request.sessionToken = new google.maps.places.AutocompleteSessionToken(); } declare global { interface Window { init: () => void; } } window.init = init;
JavaScript
let titleElement; let resultsContainerElement; let inputElement; let newestRequestId = 0; // Add an initial request body. const 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', }; function init() { titleElement = document.getElementById('title'); resultsContainerElement = document.getElementById('results'); inputElement = document.querySelector('input'); inputElement.addEventListener('input', makeAutocompleteRequest); refreshToken(request); } async function makeAutocompleteRequest(inputEvent) { // Reset elements and exit if an empty string is received. if (inputEvent.target.value == '') { titleElement.innerText = ''; resultsContainerElement.replaceChildren(); return; } // Add the latest char sequence to the request. request.input = inputEvent.target.value; // To avoid race conditions, store the request ID and compare after the request. const requestId = ++newestRequestId; // Fetch autocomplete suggestions and show them in a list. // @ts-ignore const { suggestions } = await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request); // If the request has been superseded by a newer request, do not render the output. if (requestId !== newestRequestId) return; titleElement.innerText = `Query predictions for "${request.input}"`; // Clear the list first. resultsContainerElement.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 item element. const li = document.createElement('li'); li.appendChild(a); resultsContainerElement.appendChild(li); } } // Event handler for clicking on a suggested place. async function onPlaceSelected(place) { await place.fetchFields({ fields: ['displayName', 'formattedAddress'], }); const placeText = document.createTextNode(`${place.displayName}: ${place.formattedAddress}`); resultsContainerElement.replaceChildren(placeText); titleElement.innerText = 'Selected Place:'; inputElement.value = ''; refreshToken(request); } // Helper function to refresh the session token. function refreshToken(request) { // Create a new session token and add it to the request. request.sessionToken = new google.maps.places.AutocompleteSessionToken(); } 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=AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8&callback=init&libraries=places&v=weekly" defer ></script> </body> </html>