/*
The addressAutocomplete takes as parameters:
- a container element (div)
- callback to notify about address selection
*/
function addressAutocomplete(containerElement, callback) {
// create input element
var inputElement = document.createElement("input");
inputElement.setAttribute("type", "text");
inputElement.setAttribute("placeholder", "Enter an address here");
containerElement.appendChild(inputElement);
/* Current autocomplete items data (GeoJSON.Feature) */
var currentItems;
/* Active request promise reject function. To be able to cancel the promise when a new request comes */
var currentPromiseReject;
/* Execute a function when someone writes in the text field: */
inputElement.addEventListener("input", function(e) {
var currentValue = this.value;
/* Close any already open dropdown list */
closeDropDownList();
// Cancel previous request promise
if (currentPromiseReject) {
currentPromiseReject({
canceled: true
});
}
/* Create a new promise and send geocoding request */
var promise = new Promise((resolve, reject) => {
currentPromiseReject = reject;
var apiKey = "47f523a46b944b47862e39509a7833a9";
var url = `https://api.geoapify.com/v1/geocode/autocomplete?text=${encodeURIComponent(currentValue)}&limit=5&apiKey=${apiKey}`;
fetch(url)
.then(response => {
// check if the call was successful
if (response.ok) {
response.json().then(data => resolve(data));
} else {
response.json().then(data => reject(data));
}
});
});
promise.then((data) => {
currentItems = data.features;
/*create a DIV element that will contain the items (values):*/
var autocompleteItemsElement = document.createElement("div");
autocompleteItemsElement.setAttribute("class", "autocomplete-items");
containerElement.appendChild(autocompleteItemsElement);
/* For each item in the results */
data.features.forEach((feature, index) => {
/* Create a DIV element for each element: */
var itemElement = document.createElement("DIV");
/* Set formatted address as item value */
itemElement.innerHTML = feature.properties.formatted;
/* Set the value for the autocomplete text field and notify: */
itemElement.addEventListener("click", function(e) {
inputElement.value = currentItems[index].properties.formatted;
callback(currentItems[index]);
/* Close the list of autocompleted values: */
closeDropDownList();
});
autocompleteItemsElement.appendChild(itemElement);
});
}, (err) => {
if (!err.canceled) {
console.log(err);
}
});
});
function closeDropDownList() {
var autocompleteItemsElement = containerElement.querySelector(".autocomplete-items");
if (autocompleteItemsElement) {
containerElement.removeChild(autocompleteItemsElement);
}
}
}
addressAutocomplete(document.getElementById("autocomplete-container"), (data) => {
console.log("Selected option: ");
console.log(data);
});
<div class="autocomplete-container" id="autocomplete-container"></div>
body {
font: 16px;
background: #f3f5f6;
}
.autocomplete-container {
/*the container must be positioned relative:*/
position: relative;
}
.autocomplete-container input {
width: calc(100% - 43px);
outline: none;
border: 1px solid rgba(0, 0, 0, 0.2);
padding: 10px;
padding-right: 31px;
font-size: 16px;
}
.autocomplete-items {
position: absolute;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.1);
border-top: none;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
top: calc(100% + 2px);
left: 0;
right: 0;
}
.autocomplete-items div {
padding: 10px;
cursor: pointer;
background-color: #fff;
}
.autocomplete-items div:hover {
/*when hovering an item:*/
background-color: rgba(0, 0, 0, 0.1);
}