使用 Editor 進行地址自動完成
當使用 Editor 建立資料輸入表單時,開發人員可以透過多種方式讓最終使用者的生活更加輕鬆——乾淨、簡潔和清晰的表單是 Editor 的優勢之一,但您也可以使用查找和自動完成功能,讓最終使用者的資料輸入更容易。您很可能在註冊服務或在網路上運送物品時遇到過地址自動完成功能——本文將深入探討如何在 Editor 中實現此功能。
範例
首先,讓我們直接跳到一個可運作的範例,以便您了解我們要建構的內容——以下是一個包含三個虛構地址的表格。它完全可以像使用 Editor 的常規 DataTable 一樣進行編輯(在本例中為本機編輯——此範例沒有後端資料庫)。本部落格文章中感興趣的部分是,如果您建立新記錄或編輯現有記錄——第二個欄位不是資料欄位,而是一個輸入欄位,讓使用者可以開始輸入地址,然後將使用 優秀的 Geoapify API 查找地址。系統會向最終使用者(在本例中是您!)顯示一個選項列表,並在他們繼續輸入時進行完善,讓他們點擊其中一個以自動完成表單中的欄位。
姓名 | 房屋 | 街道 | 城市 | 郡 | 州 | 郵遞區號 | 國家/地區 | |
---|---|---|---|---|---|---|---|---|
Airi Satou | The Ivies | Glebe Close | 倫敦 | 倫敦 | NW11 9TU | 英國 | ||
Hope Fuentes | 392 | 楓樹街 | 洛杉磯 | 加利福尼亞州 | 90017 | 美國 | ||
Serge Baldwin | 28 | Chemin Du Lavarin Sud | 卡昂 | 下諾曼第 | 14000 | 法國 |
運作方式
可編輯的 DataTable 是一個包含七個欄位的簡單表格,而 Editor 使用一個額外的欄位來匹配該表格,以進行地址查找。您可以在此網站找到許多關於如何設定 DataTables 和 Editor 的範例和文件——為簡潔起見,我不會在此處重新說明使用的組態,但是,一個值得注意的點是 lookup
欄位已將 fields.submit
選項設定為 false
,因為該欄位的資料在提交到伺服器時不相關——它是一個僅限於用戶端的欄位。
DataTables 和 Editor 的初始化程式碼為
const editor = new DataTable.Editor({
fields: [
{
label: 'Name:',
name: 'name'
},
{
label: 'Address lookup:',
labelInfo: 'Start typing your address to automatically look it up.',
name: 'lookup',
submit: false
},
{
label: 'House name / number:',
name: 'house'
},
{
label: 'Street:',
name: 'street'
},
{
label: 'City:',
name: 'city'
},
{
label: 'County:',
name: 'county'
},
{
label: 'State:',
name: 'state'
},
{
label: 'Postcode / ZIP:',
name: 'postcode'
},
{
label: 'Country:',
name: 'country'
}
],
table: '#addresses'
});
new DataTable('#addresses', {
columns: [
{
className: 'dtr-control',
orderable: false,
targets: 0,
defaultContent: ''
},
{ data: 'name' },
{ data: 'house' },
{ data: 'street' },
{ data: 'city' },
{ data: 'county' },
{ data: 'state' },
{ data: 'postcode' },
{ data: 'country' }
],
layout: {
topStart: {
buttons: [
{ extend: 'create', editor: editor },
{ extend: 'edit', editor: editor },
{ extend: 'remove', editor: editor }
]
}
},
order: [1, 'asc'],
responsive: {
details: {
type: 'column'
}
},
select: true
});
地址查找
在 Editor 中,當您希望根據欄位中的輸入值發生某些事情時,我們使用 dependent()
方法。在這種情況下,我們想要監聽 lookup
欄位的變更,然後觸發對 Geoapify 自動完成 API 的呼叫(他們的 API 文件完整)。
關於我們對 dependent()
的使用,有兩個重點
- 我們想要在使用者輸入時採取行動,而不僅僅是等待使用者完成輸入並將焦點從欄位移開(例如,
change
事件,這是預設值)。為此,我們使用dependent()
的第三個參數,將監聽事件設定為input
。 - 同時,我們不想在每次按鍵時觸發 Ajax 請求——我們希望將它們分組,以免浪費 API 資源。為此,我們可以使用
DataTable.util.debounce()
公用方法。
我們的 dependent()
設定呼叫結構如下
editor.dependent(
'lookup',
DataTable.util.debounce(function (val, data, cb) {
// Ajax lookup code based on `val`
}),
{event: 'input'}
);
現在我們有了 lookup
欄位的值,我們可以前往 Geoapify API 並查詢它,以查看它認為哪些選項是可行的候選選項。為此,我們可以使用 fetch()
API
if (val) {
fetch(
'https://api.geoapify.com/v1/geocode/autocomplete?text=' +
encodeURIComponent(val) +
'&apiKey=' +
encodeURIComponent(apiKey)
)
.then((response) => response.json())
.then((json) => {
// Got our response
displayResults(editor, json);
cb({});
});
}
請注意,apiKey
變數將設定為您的 Geoapify 專案中的任何 API 金鑰(在其網站上註冊)。此外,您會看到使用空物件呼叫了 cb()
——此回呼函式是 dependent()
函式的一部分,並告知 Editor 您的相依處理常式已完成處理。在呼叫回呼函式之前,Editor 會將欄位顯示為「處理中」,讓最終使用者知道正在發生某些事情。
選項顯示
從自動完成 API 中,我們現在有了應該向最終使用者顯示的選項。為此,我們建立一個 displayResults()
函式,該函式接受 API 傳回的陣列,為每個選項建立一個 div
,然後將其插入欄位「資訊」區域。可以使用 field().fieldInfo()
方法寫入欄位資訊。
這個程式碼區塊乍看之下可能有點嚇人,但實際上它所做的只是建立一個容器 div
,然後為每個選項建立一個 div
,其中包含一堆 span
元素,用於每個地址元素。我還建立了一個 createElement()
函式(如下所示),以盡可能簡化新元素的建立。
// Display the list of addresses that have been found
function displayResults(editor, json) {
var options = createElement('div', { className: 'lookup-options' });
var addresses = json.features.slice(0, 6); // Limit to 6
addresses.forEach((full) => {
var address = full.properties;
var option = createElement('div', { className: 'lookup-option' }, null, options);
// Store for lookup if selected
option._address = address;
createElement('span', { className: 'lookup-house' }, address.housenumber || address.name, option);
createElement('span', { className: 'lookup-street' }, address.street, option);
createElement('span', { className: 'lookup-city' }, address.city, option);
createElement('span', { className: 'lookup-county' }, address.county, option);
createElement('span', { className: 'lookup-state' }, address.state, option);
createElement('span', { className: 'lookup-postcode' }, address.postcode, option);
createElement('span', { className: 'lookup-country' }, address.country, option);
});
editor.field('lookup').fieldInfo(options);
}
// Helper for creating new DOM elements
function createElement(name, props, content, appendTo) {
let el = document.createElement(name);
if (props) {
Object.assign(el, props);
}
if (content) {
el.textContent = content;
}
if (appendTo) {
appendTo.appendChild(el);
}
return el;
}
最後,使用 CSS 在網格中顯示地址選項。我使用了 flexbox,但您可以使用 CSS Grid 或其他任何您想要的選項。實際上,使用上面的函式,您可以完全控制 DOM 結構,因此您可以根據您的應用程式修改佈局!
.lookup-options {
display: flex;
flex-wrap: wrap;
gap: 0.5em;
justify-content: space-between;
}
.lookup-option {
width: calc(50% - 0.25em);
box-sizing: border-box;
padding: 1em;
border: 1px solid rgba(122, 122, 122, 0.5);
border-radius: 4px;
cursor: pointer;
}
.lookup-option span {
display: block;
}
選擇地址
我們需要完成才能獲得可運作系統的最後一個項目是允許最終使用者點擊地址,並將值插入 Editor 表單中。為此,我們在 Editor 欄位 (field().node()
) 上使用 DOM click
事件監聽器,並對其進行篩選,使其僅對選項元素 (.lookup-option
) 上的事件採取行動。如果您熟悉 jQuery 術語,這稱為委派事件處理常式,它基本上允許子元素的 DOM 元素變更(在本例中為我們的選項),同時只需要一個事件監聽器即可透過事件傳播處理事件(事件會透過 DOM 向上冒泡)
// Handle a click on an address to select it
editor.field('lookup').node().addEventListener('click', function (e) {
let option = e.target.closest('div.lookup-option');
if (option) {
// Write field values
}
});
要寫入欄位值,我們可以簡單地使用 Editor field().val()
方法為每個欄位寫入所選條目的值。請注意,在上面的 displayResults()
中,每個選項 div
都將地址物件附加為 _address
屬性。這樣做是為了在選取選項時,我們可以透過讀取該屬性從節點中簡單地擷取它
let address = option._address;
// Address was selected - fill in the Editor field values
editor.field('house').val(address.housenumber || address.name || '');
editor.field('street').val(address.street || '');
editor.field('city').val(address.city || '');
editor.field('county').val(address.county || '');
editor.field('state').val(address.state || '');
editor.field('postcode').val(address.postcode || '');
editor.field('country').val(address.country || '');
// Clear the lookup
editor.field('lookup').fieldInfo('').val('');
最後一個動作是清除查找欄位的選項和值。
將所有項目連結在一起
我在這篇文章中將所有內容分解為區塊,以便能夠解釋每個區塊。若要查看所有項目連結在一起,請查看以下檔案
此部落格文章中介紹的地址自動完成功能只是可以用於在 Editor 中自動完成資料的一個範例,並使用特定的 API。您可能有權存取不同的地址自動完成系統,或者具有完全不同的資料類型,您可以透過該資料類型執行自動完成。
希望這篇部落格文章能為您提供您需要的工具和信心,讓您能夠將類似的動作新增到您自己的表單中。如果您想出任何其他動作,請在論壇中告訴我!