Autocomplete Tutorial
Autocomplete Demo
This tutorial is a simplified version of our autocomplete demo page, which allows users to enter coordinates, a search radius, and a limit to the number of results.
Implementation
Step 1: Get an API Key
If you do not have an account, you can get a free test api key. Set $your_api_key
in Step 3 to be the value of your key.
Step 2: Build HTML
Create an input for autocomplete.
<div id="autocomplete-container">
<label>Enter business name or address</label>
<input autocomplete="off" id="autocomplete-input" placeholder='"Cost" or "3350 Scott"' type="text" name="name">
</div>
Step 3: Set key and add JavaScript handlers
Add onkeydown and oninput event listeners.
var focus = -1;
var NTK_KEY = $your_api_key; // replace this value with your own key
function initializeAutocomplete() {
var input = document.getElementById("autocomplete-input");
input.addEventListener("input", function(e) {
handleChange(this.value, input);
});
input.addEventListener("keydown", function(e) {
var listContainer = document.getElementById("list-container");
if (!listContainer) return;
var list = listContainer.getElementsByTagName("div");
if (list.length < 1) return;
switch (e.keyCode) {
case 40: // down abc
e.preventDefault();
resetActive(list);
focus++;
if (focus >= list.length) {
focus = 0;
}
setActive(list);
break;
case 38: // up
e.preventDefault();
resetActive(list);
focus--;
if (focus < 0) {
focus = list.length - 1;
}
setActive(list);
break;
case 13: // enter
if (focus > -1) {
list[focus].click();
}
break;
case 27: // esc
closeList();
break;
default:
break;
}
});
}
function setActive(list) {
if (focus == -1) return;
list[focus].classList.add("active");
}
function resetActive(list) {
if (focus == -1) return;
list[focus].classList.remove("active");
}
function closeList() {
focus = -1;
var autocompleteContainer =
document.getElementById("autocomplete-container");
var listContainer = document.getElementById("list-container");
if (listContainer) {
autocompleteContainer.removeChild(listContainer);
}
}
Step 4: Fetch data from NetToolKit
When text is entered into the input, search for business names and addresses and populate the dropdown list.
function handleChange(value, input) {
var text = encodeURIComponent(value);
// var text = value;
// To support IE include the following polyfills:
// fetch polyfill - https://github.com/github/fetch
// promise polyfill - https://github.com/taylorhakes/promise-polyfill
fetch("https://api.nettoolkit.com/v1/geo/names?key="
+ NTK_KEY + "&text=" + text)
.then((response) => {
return response.json();
})
.then((json) => {
return json.results;
})
.then((list) => {
closeList();
var listContainer = document.createElement("div");
if (list.length < 1) return;
listContainer.setAttribute("id", "list-container");
var autocompleteContainer =
document.getElementById("autocomplete-container");
autocompleteContainer.appendChild(listContainer);
for (var i = 0; i < list.length; i++) {
var item = document.createElement("div");
item.textContent = list[i].name + (list[i].address
? " (" + list[i].address + ")" : "");
item.name = list[i].name;
item.address = list[i].address;
item.latitude = list[i].latitude;
item.longitude = list[i].longitude;
// Display the latitude, longitude coordinates
item.addEventListener("click", function(e) {
if (document.getElementById("item-results")) {
autocompleteContainer.removeChild(
document.getElementById("item-results"));
}
input.value = this.address ? this.address : this.name;
var results = document.createElement("div");
results.setAttribute("id", "item-results");
// toFixed truncates rather than round,
// a more accurate method would be to use
// Math.round with a multiplier
results.textContent =
"latitude: " + this.latitude.toFixed(2) + " " +
"longitude: " + this.longitude.toFixed(2);
autocompleteContainer.appendChild(results);
closeList();
});
listContainer.appendChild(item);
}
});
}
initializeAutocomplete();
Step 5: Add styling
Add custom css.
#autocomplete-container {
width: 300px;
}
#autocomplete-input {
width: 100%;
box-sizing: border-box;
}
#list-container {
position: absolute;
color: white;
background-color: #2b2d2f;
border: 1px solid #d3d3d3;
z-index: 100;
}
#list-container div:not(:last-child) {
cursor: pointer;
border-bottom: 1px solid #d3d3d3;
}
#list-container div.active {
background-color: #4E8EF9;
color: #fff;
}
Putting all of the pieces together
<!DOCTYPE >
<html>
<head>
<style>
#autocomplete-container {
width: 300px;
}
#autocomplete-input {
width: 100%;
box-sizing: border-box;
}
#list-container {
position: absolute;
color: white;
background-color: #2b2d2f;
border: 1px solid #d3d3d3;
z-index: 100;
}
#list-container div:not(:last-child) {
cursor: pointer;
border-bottom: 1px solid #d3d3d3;
}
#list-container div.active {
background-color: #4E8EF9;
color: #fff;
}
</style>
</head>
<body>
<div id="autocomplete-container">
<label>Enter business name or address</label>
<input autocomplete="off" id="autocomplete-input" placeholder='"Cost" or "3350 Scott"' type="text" name="name">
</div>
<script>
var focus = -1;
var NTK_KEY = $your_api_key; // replace this value with your own key
function initializeAutocomplete() {
var input = document.getElementById("autocomplete-input");
input.addEventListener("input", function(e) {
handleChange(this.value, input);
});
input.addEventListener("keydown", function(e) {
var listContainer = document.getElementById("list-container");
if (!listContainer) return;
var list = listContainer.getElementsByTagName("div");
if (list.length < 1) return;
switch (e.keyCode) {
case 40: // down abc
e.preventDefault();
resetActive(list);
focus++;
if (focus >= list.length) {
focus = 0;
}
setActive(list);
break;
case 38: // up
e.preventDefault();
resetActive(list);
focus--;
if (focus < 0) {
focus = list.length - 1;
}
setActive(list);
break;
case 13: // enter
if (focus > -1) {
list[focus].click();
}
break;
case 27: // esc
closeList();
break;
default:
break;
}
});
}
function setActive(list) {
if (focus == -1) return;
list[focus].classList.add("active");
}
function resetActive(list) {
if (focus == -1) return;
list[focus].classList.remove("active");
}
function closeList() {
focus = -1;
var autocompleteContainer =
document.getElementById("autocomplete-container");
var listContainer = document.getElementById("list-container");
if (listContainer) {
autocompleteContainer.removeChild(listContainer);
}
}
function handleChange(value, input) {
var text = encodeURIComponent(value);
// var text = value;
// To support IE include the following polyfills:
// fetch polyfill - https://github.com/github/fetch
// promise polyfill - https://github.com/taylorhakes/promise-polyfill
fetch("https://api.nettoolkit.com/v1/geo/names?key="
+ NTK_KEY + "&text=" + text)
.then((response) => {
return response.json();
})
.then((json) => {
return json.results;
})
.then((list) => {
closeList();
var listContainer = document.createElement("div");
if (list.length < 1) return;
listContainer.setAttribute("id", "list-container");
var autocompleteContainer =
document.getElementById("autocomplete-container");
autocompleteContainer.appendChild(listContainer);
for (var i = 0; i < list.length; i++) {
var item = document.createElement("div");
item.textContent = list[i].name + (list[i].address
? " (" + list[i].address + ")" : "");
item.name = list[i].name;
item.address = list[i].address;
item.latitude = list[i].latitude;
item.longitude = list[i].longitude;
// Display the latitude, longitude coordinates
item.addEventListener("click", function(e) {
if (document.getElementById("item-results")) {
autocompleteContainer.removeChild(
document.getElementById("item-results"));
}
input.value = this.address ? this.address : this.name;
var results = document.createElement("div");
results.setAttribute("id", "item-results");
// toFixed truncates rather than round,
// a more accurate method would be to use
// Math.round with a multiplier
results.textContent =
"latitude: " + this.latitude.toFixed(2) + " " +
"longitude: " + this.longitude.toFixed(2);
autocompleteContainer.appendChild(results);
closeList();
});
listContainer.appendChild(item);
}
});
}
initializeAutocomplete();
</script>
</body>
</html>