Skip to content

Adding AJAX autocomplete using Typeahead & Bloodhound

Peter Klein edited this page Nov 7, 2018 · 4 revisions

This example shows how to add autocomplete/autosuggest using Twitter Typeahead + Bloodhound plugins.

The example uses the Danish Roadname API (because it doesn't require any authentication 😄), but you can use whatever API you like (See the documentation for Typeahead/Bloodhound)

First, you will need to add these 2 javascript libraries to your setup

jQuery - jquery.min.js
Typeahead + Bloodhound - typeahead.bundle.min.js

Next, you will have to add some CSS to style the autocomplete drop-down.

Here's an example setup:

.tt-query {
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.tt-hint {
  color: #999;
}
.tt-menu {
  width: 100%;
  min-width: 200px;
  padding: 4px 0;
  background-color: #fff;
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, 0.2);
  border-radius: 4px;
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}
.tt-suggestion {
  padding: 3px 20px;
  line-height: 24px;
}
.tt-suggestion.tt-cursor,
.tt-suggestion:hover {
  color: #fff;
  background-color: #0097cf;
}
.tt-suggestion p {
  margin: 0;
}
.input-loading {
}
.input-loading:after {
  position: absolute;
  top: 8px;
  right: 8px;
  content: "\e030";
  font-family: "Glyphicons Halflings";
  color: #0097cf;
  font-size: 20px;
  font-weight: 400;
  line-height: 1;
  transform: rotate(0deg);
  animation: spinner 1s linear infinite;
}
@keyframes spinner {
  100% {
    transform: rotate(359deg);
  }
}

And finally, the JavaScript code to initialize the Typeahead/Bloodhound engine and attach it to a JSON-Editor input field.

// Initialize the Typeahead/Bloodhound engine
// (See Typeahead/Bloodhound documentation for more info)
var roadEngine = new Bloodhound({
  datumTokenizer: Bloodhound.tokenizers.obj.whitespace("tekst"),
  queryTokenizer: Bloodhound.tokenizers.whitespace,
  remote: {
    url: "https://dawa.aws.dk/vejnavne/autocomplete?q=%QUERY",
    wildcard: "%QUERY",
    cache: true
  }
});
roadEngine.clearRemoteCache();
roadEngine.initialize();

// Typeahead/Bloodhound dataset
var roadEngineDataset = {
  name: "road",
  display: "tekst",
  source: roadEngine.ttAdapter()
}
// Typeahead/Bloodhound config options
var roadEngineConfig = {
  autoselect: true,
  highlight: true,
  hint: true,
  minLength: 3
}

// The JSON-Editor Schema
var options = {
  "theme": "bootstrap3",
  "iconlib": "bootstrap3",
  "schema": {
    "title": "Typeahead/Bloodhound example",
    "type": "object",
    "properties": {
      "roadname": {
        "type": "string",
        "title": "Roadname"
      }
    }
  }
};

var element = document.getElementById('form');
// Initialize JSON-Editor
var editor = new JSONEditor(element, schema);

// When JSON-Editor is ready perform action on field(s)
editor.on('ready', function() {
  // Get the JSON-Editor for the "roadname" field
  var ed = editor.getEditor('root.roadname');

  if (ed) {
    // Attach the Typeahead/Bloodhound engine to the JSON-Editor input field
    $(ed.input).typeahead(roadEngineConfig, roadEngineDataset)
    .on("typeahead:asyncrequest", function() {
      // Enable spinner
      $(ed.input).parent().addClass("input-loading");
    })
    .on("typeahead:asynccancel typeahead:asyncreceive", function() {
      // Disable spinner
      $(ed.input).parent().removeClass("input-loading");
    });

    // Change parent (wrapper) display from inline-block to block
    $(ed.input).parent().css("display", "block");
  }
});

Once you have done the above, try typing a couple letters of a road name (Danish road name API is used in example). If everything works, you should see a drop-down with a list of suggestions.