
Gõ “Landmark 81” vào ô địa chỉ rồi dừng lại. Thứ người dùng cần tiếp theo là vài lựa chọn có ngữ cảnh, chưa phải một tọa độ được hệ thống tự chọn. Sau khi khách chọn đúng tòa nhà, ứng dụng mới lấy vị trí và hỏi điểm đó có phải cổng nhận hàng không. Luồng hai bước này là nền tảng để tích hợp API tìm kiếm địa chỉ Việt Nam cho một biểu mẫu dùng được trong thực tế.
TrackAsia tài liệu hóa Autocomplete v2 cho gợi ý và Place Detail v2 để lấy thông tin qua place_id. Search v2 là dịch vụ liên quan nhưng dành cho cách truy vấn khác, chẳng hạn ứng dụng đã có một chuỗi tìm kiếm đầy đủ hơn.[2][3][4] Bài này bắt đầu bằng luồng gợi ý rồi lấy chi tiết, sau đó giải thích cách lưu, xử lý lỗi và xác nhận để kết quả tìm kiếm trở thành địa chỉ vận hành.
Thử toàn bộ luồng bằng một tệp HTML
Lưu mã dưới đây thành address-demo.html rồi mở bằng trình duyệt hiện đại. Mẫu dùng public_key giới hạn dành cho thử nghiệm theo tài liệu.[2][4] Đây không phải khóa bí mật hay hạn mức dành cho hệ thống thật. Nếu trình duyệt chặn yêu cầu từ tệp cục bộ, chạy python3 -m http.server 8080 tại thư mục chứa tệp rồi mở http://localhost:8080/address-demo.html.
Mẫu cố ý hiện hồ sơ đã chọn dưới dạng chữ để tập trung vào thứ tự gọi và ánh xạ dữ liệu. Nó có danh sách gợi ý, nút chọn dùng được bằng bàn phím, hủy yêu cầu cũ, chờ ngừng gõ và báo lỗi rõ. Khi làm sản phẩm, có thể bổ sung điều khiển bằng phím mũi tên cho danh sách mà giữ nguyên logic gọi dịch vụ.
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>TrackAsia address search</title><style>body{max-width:700px;margin:32px auto;padding:16px;font:17px/1.6 system-ui}input,button{font:inherit;padding:10px}input{width:90%}button{display:block;margin:8px 0;text-align:left;width:100%}pre{white-space:pre-wrap;overflow-wrap:anywhere}#status{min-height:2em}</style><h1>Find and confirm an address</h1><p>Limited public test key. Select a suggestion to resolve coordinates.</p><label for="query">Address or place</label><input id="query" autocomplete="off" placeholder="Landmark 81"><p id="status" role="status"></p><div id="results"></div><pre id="selected"></pre><script>
const input=document.querySelector('#query');
const list=document.querySelector('#results');
const status=document.querySelector('#status');
const selected=document.querySelector('#selected');
let timer,controller,version=0;
async function request(path,params,signal){
const url=new URL('https://maps.track-asia.com/api/v2/place/'+path+'/json');
url.search=new URLSearchParams({...params,key:'public_key',new_admin:'true',include_old_admin:'true'});
const response=await fetch(url,{signal});
if(!response.ok)throw new Error('HTTP '+response.status);
const data=await response.json();
if(data.status==='ZERO_RESULTS')return data;
if(data.status!=='OK')throw new Error(data.status||'Invalid response');
return data;
}
input.addEventListener('input',()=>{
clearTimeout(timer);controller?.abort();version++;
const current=version,text=input.value.trim();
list.replaceChildren();selected.textContent='';status.textContent='';
if(text.length<3)return;
controller=new AbortController();const signal=controller.signal;
timer=setTimeout(async()=>{
status.textContent='Searching…';
try{
const data=await request('autocomplete',{input:text,size:'5'},signal);
if(current!==version)return;
const items=data.predictions||[];
status.textContent=items.length?'Select a place.':'No results. Try more context.';
for(const item of items){
const button=document.createElement('button');button.type='button';
button.textContent=item.description||item.name||item.place_id;
button.addEventListener('click',()=>choose(item,current));list.append(button);
}
}catch(error){if(error.name!=='AbortError'&¤t===version)status.textContent='Search failed: '+error.message;}
},300);
});
async function choose(item,current){
controller?.abort();controller=new AbortController();
list.replaceChildren();status.textContent='Loading place…';
try{
const data=await request('details',{place_id:item.place_id},controller.signal);
if(current!==version)return;
const place=data.result,point=place?.geometry?.location;
if(!Number.isFinite(point?.lat)||!Number.isFinite(point?.lng))throw new Error('No usable coordinates');
input.value=place.formatted_address||item.description;
selected.textContent=JSON.stringify({place_id:place.place_id,address:place.formatted_address,old_address:place.old_formatted_address??null,lat:point.lat,lng:point.lng},null,2);
status.textContent='Place selected. Confirm the delivery entrance in your application.';
}catch(error){if(error.name!=='AbortError'&¤t===version)status.textContent='Place failed: '+error.message;}
}
</script></html>
Gõ từ ba ký tự, chờ gợi ý rồi chọn một kết quả. Ngưỡng ba ký tự và khoảng chờ 300 mili giây là lựa chọn của ví dụ, không phải yêu cầu hay cam kết hiệu năng của TrackAsia. Hồ sơ bên dưới gồm mã địa điểm, địa chỉ hiện tại, địa chỉ cũ nếu có, cùng vĩ độ và kinh độ có tên rõ. Thứ tự gợi ý và nội dung có thể thay đổi khi dữ liệu được cập nhật.
Thông báo cuối nhắc xác nhận cổng giao trong ứng dụng. Việc chọn một địa điểm chưa chứng minh đã giải quyết xong mọi yêu cầu kiểm tra địa chỉ. Điều này đặc biệt quan trọng với chung cư, khu công nghiệp hoặc tòa nhà có điểm tham chiếu khác cổng xe vào.
Vì sao cần hai lượt gọi?
Autocomplete trả danh sách ứng viên. Tài liệu mô tả place_id, description, formatted_address và các trường phục vụ hiển thị như structured_formatting trong từng prediction.[2] Người dùng dựa vào ngữ cảnh đó để chọn nơi mình muốn. Lấy đầy đủ chi tiết cho mọi gợi ý sẽ phát sinh thêm công việc trước khi biết ứng viên nào thật sự cần.
Sau khi chọn, gửi mã của kết quả tới /api/v2/place/details/json. Phản hồi được tài liệu mô tả đặt thông tin địa điểm trong result, tọa độ tại result.geometry.location.lat và .lng.[4] Đừng tìm tọa độ ở gốc phản hồi gợi ý hoặc coi mã địa điểm là một cặp tọa độ có thể tự phân tích.
Dùng URLSearchParams thay vì nối thẳng câu người dùng gõ vào URL. Dấu tiếng Việt, khoảng trắng và dấu câu cần được mã hóa đúng. Hàm gọi chung cũng giữ lựa chọn hành chính giống nhau giữa gợi ý và chi tiết, tránh việc địa chỉ trước và sau chọn đổi cách trình bày chỉ do hai yêu cầu khác cấu hình.
Mẫu kiểm tra cả trạng thái HTTP và status trong JSON. HTTP 200 chỉ cho biết đã nhận được phản hồi; nội dung vẫn có thể báo không có kết quả hoặc lỗi ứng dụng. ZERO_RESULTS nên dẫn đến thông báo tìm kiếm rỗng. Yêu cầu sai hoặc dịch vụ không sẵn sàng phải được phân biệt với tìm thành công nhưng không có nơi phù hợp.[2][4]
Đừng để phản hồi cũ sửa lựa chọn mới
Người dùng gõ “Land”, dừng một nhịp rồi gõ hết “Landmark 81”. Yêu cầu đầu nếu chậm có thể về sau yêu cầu thứ hai. Nếu không kiểm soát, danh sách trông như quay lại truy vấn cũ. Đây là lỗi tranh chấp trạng thái trong ứng dụng, không phải bằng chứng dịch vụ hiểu sai câu mới nhất.
Mẫu dùng hai lớp bảo vệ. AbortController hủy yêu cầu trước khi có thao tác nhập tiếp. Biến version tăng dần còn ngăn phản hồi hết hiệu lực được vẽ lên màn hình. Hủy giúp giảm xử lý thừa phía trình duyệt; kiểm tra phiên bản giữ trạng thái đúng cả khi phản hồi đã về ngay trước lúc bị hủy.
Mỗi lần sửa chữ, hồ sơ đã chọn bị xóa ngay. Giữ tọa độ cũ trong khi cho nhập địa chỉ mới tạo ra một lỗi khó thấy: màn hình nói một nơi, đơn vẫn lưu điểm khác. Cần phân biệt đang nhập, đang có gợi ý và đã chọn, dù giao diện nhìn khá đơn giản.
Điều tương tự xảy ra khi lấy chi tiết. Khách có thể chọn gợi ý rồi sửa ô nhập trước khi chi tiết về. Phản hồi đó không được tự ghi đè phần vừa gõ. Hàm chọn kiểm tra phiên bản trước khi lưu hồ sơ đã phân giải.
Ánh xạ sang hồ sơ đơn thay vì lưu nguyên phản hồi
Một mô hình khởi đầu có thể gồm original_input, provider, place_id, formatted_address, old_formatted_address, lat, lng, confirmation_state và confirmed_at. Đây là các trường gợi ý cho ứng dụng, không phải bộ trường TrackAsia bắt buộc doanh nghiệp phải dùng.
Lưu câu nhập gốc trước khi thay nội dung ô bằng địa chỉ chuẩn hóa. Ví dụ tối giản thay ô nhập để dễ quan sát; trang đặt hàng thật nên giữ câu ban đầu trong trạng thái đơn. Khách đôi khi gõ thêm tên nội bộ của tòa nhà hoặc ngữ cảnh không thuộc chuỗi địa chỉ tiêu chuẩn.
Mã địa điểm thuộc phạm vi nhà cung cấp. Không gửi mã TrackAsia sang dịch vụ chi tiết của bên khác và không dùng nó thay mã khách hàng do doanh nghiệp quản lý. Nên giữ mã khách hoặc mã điểm riêng rồi lưu mã nhà cung cấp như thông tin nguồn vị trí.
Lưu tọa độ bằng số với tên thuộc tính. Khi thêm bản đồ, chuyển đổi theo định dạng thư viện tại một chỗ. Khi gọi API tiếp theo, xem đúng quy ước dịch vụ đó; Directions v2 và VRP v1 của TrackAsia có biểu diễn tọa độ khác nhau trong tài liệu.[5][6] Quy tắc nhỏ này tránh một lỗi tích hợp dễ bị hiểu nhầm là tìm sai địa chỉ.
Thử với mã nguồn: Tìm và xác nhận địa chỉ
Nhập Landmark 81, chọn một gợi ý rồi đọc chi tiết địa điểm và tọa độ trả về.
Ví dụ gọi API dùng public_key giới hạn; ảnh chụp phiên chạy của mã nguồn bên dưới.
Giải nén ZIP, chạy python3 -m http.server 8080 trong thư mục vừa giải nén, rồi mở http://localhost:8080/index-vi.html. README tiếng Việt và tiếng Anh nằm trong ZIP; không cần npm hay bước build.

Dùng địa chỉ hành chính cũ và mới thế nào?
Tài liệu v2 có new_admin=true và include_old_admin=true; lấy thêm địa chỉ cũ áp dụng khi bật chế độ hành chính mới.[2][4] Mẫu gửi nhất quán ở cả hai bước và chỉ đọc địa chỉ cũ khi trường đó tồn tại. Không nên xây một trường nhập bắt buộc dựa trên thuộc tính tùy chọn của phản hồi.
Địa chỉ hiện tại và cách gọi cũ có mục đích khác nhau. Dạng hiện tại hỗ trợ hiển thị hôm nay; dạng cũ giúp người dùng nhận ra nơi quen hoặc hỗ trợ tra đơn trước. Đừng tự sửa địa chỉ đã in trên đơn hoàn tất chỉ vì lần tra hiện tại trả cách trình bày khác.
Nếu cần phân tích thành phần, đọc theo types thay vì vị trí trong mảng. Phần tử thứ ba không luôn là cùng một cấp hành chính. Tài liệu chi tiết mô tả tên, loại và mã hành chính trong các thành phần, với dữ liệu phụ thuộc kết quả.[4]
Ứng dụng cũng không nên bắt buộc một cây ba cấp khi phản hồi thực tế không có cấp trung gian cơ sở dữ liệu cũ mong đợi. Nếu kế toán hoặc báo cáo cần một mã cụ thể, coi đó là quy tắc tích hợp cần kiểm tra riêng. Không tự tạo giá trị còn thiếu trong trình duyệt chỉ để biểu mẫu qua được kiểm tra.
Khi nào chuyển sang Search?
Người đang gõ cần danh sách thay đổi theo câu nhập. Nhân viên điều phối dán nguyên địa chỉ hoặc quy trình nhập dữ liệu đã có truy vấn đầy đủ có thể phù hợp Search hơn. TrackAsia mô tả Search v2 riêng với Autocomplete.[2][3] Chọn theo thao tác và cấu trúc phản hồi thực tế, không coi hai endpoint thay thế nhau hoàn toàn.
Không nên làm sạch cả danh sách địa chỉ bằng cách giả lập mọi bản ghi thành một lần gõ gợi ý. Cần định nghĩa khớp thành công là gì, ai xem các ứng viên mơ hồ và lưu chuỗi gốc ở đâu. Kết quả đứng đầu chưa tự trở thành vị trí doanh nghiệp đã xác nhận.
Với đơn giao hàng, bước xác nhận có thể gồm ghim bản đồ, ghi chú cổng và hành động đồng ý rõ. Nếu khách chỉnh ghim, lưu điểm giao riêng với vị trí tham chiếu của nhà cung cấp. Nếu không, lần tải chi tiết sau dễ làm mất điều chỉnh hữu ích đó.
Kết quả rỗng vẫn cần một đường đi tiếp
Khách không tìm được địa chỉ cần biết có thể làm gì tiếp theo: thêm ngữ cảnh, nhập tay hoặc gửi để nhân viên kiểm tra. Đánh dấu thông tin nhập tay là chưa xác nhận thay vì hiện trạng thái thành công giống một điểm đã được phân giải và đối chiếu.
Nếu gợi ý không liên quan, xem câu truy vấn và ngữ cảnh địa lý trước khi đổi logic. Tài liệu Autocomplete có tham số location theo vĩ độ,kinh độ.[2] Chỉ dùng khi có điểm tham chiếu có ý nghĩa; vị trí thiết bị cũ có thể làm trải nghiệm lệch khỏi khu vực khách đang tìm.
Nếu không hiện gì, mở bảng mạng của trình duyệt. Kiểm tra endpoint, trạng thái HTTP, trạng thái ứng dụng và cấu trúc phản hồi. Tệp cục bộ bị chặn nhưng localhost chạy được là vấn đề nguồn yêu cầu của trình duyệt, không phải cách viết địa chỉ. Một lượt gọi thành công từ máy chủ chưa chứng minh trình duyệt có thể gọi chéo nguồn tương tự.
Khi lấy chi tiết lỗi sau lúc chọn, giữ chữ ứng viên nhưng không âm thầm xác nhận tọa độ. Cho thử lại hoặc quay về danh sách. Thông báo nên nói chưa tải được thông tin địa điểm, không kết luận địa chỉ không tồn tại.
Chuẩn bị dùng thật sau khi đã hiểu luồng
Thay khóa thử bằng cấu hình tài khoản phù hợp. Xác nhận hình thức giới hạn được hỗ trợ, quy tắc sử dụng và điều kiện thương mại hiện hành. Khóa gửi xuống trình duyệt nhìn thấy được; không nhét bí mật máy chủ vào tệp HTML rồi coi đó là cách bảo vệ.
Một lớp trung gian phía máy chủ có thể tập trung quyền truy cập và nhật ký, nhưng cũng là dịch vụ cần vận hành thêm. Chọn khi thực sự cần các trách nhiệm đó, không biến nó thành thủ tục bắt buộc chỉ để thử gợi ý. Dù kiến trúc nào, hạn chế địa chỉ cá nhân trong log và dùng mã tham chiếu để hỗ trợ tra lỗi.
Theo dõi cả thao tác người dùng lẫn số yêu cầu. Có thể đo thời gian tới lúc xác nhận, tỷ lệ tìm rỗng, sửa thủ công và bỏ dở. Tách lượt thử lại khỏi lỗi lấy chi tiết. Số lượt gọi tăng có thể do khách đang loay hoay, chưa chắc là tăng trưởng hữu ích.
Trước khi mở thật, thử truy vấn không dấu, tòa nhà trùng tên, địa chỉ thiếu, mất mạng, phản hồi về muộn và sửa chữ sau khi chọn. Nhờ người vận hành kiểm tra cổng của các điểm đại diện. Luồng đạt yêu cầu khi giúp khách xác nhận được vị trí dùng được và xử lý điều chưa chắc chắn rõ ràng, không chỉ khi gợi ý đầu tiên xuất hiện.