Autocomplete Tutorial

Autocomplete Demo



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>
<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>