is a javascript library enhancing Lea Verou's autocomplete / autosuggest / typeahead / inputsearch Awesomplete widget.

AwesompleteUtil adds the following features:

  • Dynamic remote data loading; based on what is typed-in it performs an ajax lookup.
  • Allow HTML markup in the shown items. Show value with description. Optionally search in the description text.
  • Show when there is an exact match.
  • Show when there isn't a match.
  • When there is an exact match show related data (supplied in the remote data) in other parts of the page.
  • Select the highlighted item when tab-key is used.

AwesompleteUtil provides enough hooks to keep the agility which the Awesomplete widget has.

The only dependency of AwesompleteUtil is Awesomplete. Together it is less than 5KB minified brotlified. It runs on modern browsers; Chrome, Safari, Edge, Firefox.

The lucky users of Phoenix can use the Awesomplete form helper to generate most of the javascript code.

Examples

Github username search
Example demonstrates:
  • Dynamic data loading.
  • Show related data of selected item.
This Github API will not show suggestions anymore if the API rate limit is exceeded for your IP address.

Enter a username:

Photo or avatar
avatar image
This example will show suggestions from the Github API. This REST API also returns avatar url's. When there is an exact match, the avatar url will be set in the IMG tag to show the avatar picture.

HTML

<input id="user_name1" class="form-control" 
       name="user[name1]" type="text" >
          
<img id="awe-avatar-img" alt="avatar image" width="100px" height="100px" >

Javascript

The maxItems parameter indicates that maximum 10 suggestions must be shown in the dropdown.

The per_page parameter in the url tells the server to return maximum 30 suggestions per call.

The limit parameter informs the AwesompleteUtil component that normally 30 results can be expected. If there are less than 30 results, any additional characters in the search phrase won't need a new server call, because all the matching suggestions are already retrieved.

The client-side suggestions filter must be made consistent with the search functionality of the REST API. In this case, the server will only return usernames that start with the entered text, and the client-side filter should work in the same way.

The item parameter is configured to highlight only matching text at the beginning of the suggestions, to clearly indicate why these suggestions are shown.

iTunes artist search
Example demonstrates:
  • Dynamic data loading.
  • Custom search filter.
  • Custom text highlighter.
Obviously we cannot load all artists known by iTunes in the browsers memory, so that's why we use here dynamic data loading. The search starts if 3 characters are entered.
Enter an artist name:
Nothing unusal in the input control:

HTML

<input class="form-control" id="user_artist1" name="user[artist1]" type="text" >
The standard supplied 'starts-with' and 'contains' filters don't exactly match with how iTunes searches (Elasticsearch). iTunes searches words, you can search for 'Michael Jackson' or 'Jackson Michael' and get the same results. Thats why a filter called 'filterWords' is used that filters on the words entered. To highlight the words in the list of suggestions a function called 'itemWords' is used.
A limit of -1 is specified to force it to requery if more characters are typed. The service search for whole words, so when a part of the word is entered and doesn't result in hits, but this doesn't mean that there wouldn't be more results if more characters are typed. For example: search for 'jackso' results in 1 hit, but 'jackson' gives a lot more results.

The iTunes service doesn't support wildcards but others (like Elasticsearch) do. Assuming that the user is completing the last word while typing, you could add a * wildcard at the end of the search url with the urlEnd: '*' configuration to search the last word starting with the typed letters.

Javascript

iTunes track search
Example demonstrates:
  • Dynamic data loading.
  • Show related data of selected item.
Enter a song title:
Artists
Album
album image
The creation of the Awesomplete object below is almost the same as in the 'iTunes artist search' example.

HTML

<input id="user_track1" class="form-control" 
       name="user[track1]" type="text" >

Javascript

Unfortunetly we cannot instruct to iTunes to sort on song title length. If you search for songs with only one or two words, it might be that the desired song is not in the first 10 shown results.
Combobox with countries
Example demonstrates:
  • Combobox.
  • Use remote service which returns everything; load all.
Input control:

HTML

<input id="user_combocountry" class="form-control" 
       name="user[combocountry]" type="text" >
  <span class="input-group-btn">
     <button class="dropdown-btn" id="awe_btn_user_combocountry" type="button" tabindex="-1">
        <span class="caron">&#9660;</span>
     </button>
  </span>
The combobox is useful when there are only a few items in the list. Here we use 8 maxItems, so when the combobox is opened, only the first 8 countries are shown. The shortest country names are shown first.

Javascript

The prepop:true makes sure that the countries are loaded during page load.
Connect as user to host
Example demonstrates:
  • Type user name and get suggestions for hostnames; autocomplete after a certain character.
  • Show descriptions in the suggestion list.
  • Load suggestions from JSON file.
Enter for example 'root@192.168.1.1'
Input control:

HTML

<input id="user_host" class="form-control" 
       name="user[host]" type="text" >

Javascript

Country iso code
Example demonstrates:
  • Use remote service that doesn't return a list but a single entry to verify input.
  • Show related data if entry found.
  • Handle HTTP 404 status with custom ajax function.
Enter for example 'usa'
This is actually not an autocomplete, but it does verify the input.

HTML

<input id="user_country_iso" class="form-control" 
       name="user[iso-country]" type="text" >
  <span id="awe-country-name"></span>
The remote service returns a HTTP status 404 if the searched value is not found. The default ajax function only processes responses with HTTP OK status 200. The ajax404 function below replaces the onload function to set the empty list if a 404 is received.

Javascript

A limit:1 tells that not more than 1 result is expected, so the JSON service doesn't have to return an array. With limit:0 it will always re-query if more characters are typed.
Colors
Example demonstrates:
  • Suggestion list with value and label as part of page source.
  • Label with HTML markup.
  • Show data of initial/autofill value; Prepopulation event during page load
Enter a color:
Input control:

HTML

<input id="user_color" class="form-control" 
       name="user[color]" type="text" value="purple" >
  <div><span id="awe-color-result"></span> &#x21B2;</div>
Below the Awesomplete object is created

Javascript

Notice the prepop property and the startCopy function call. The initial/autofilled value of input-control triggers the copy action, and the label is copied to the span-tag with id 'awe-color-result' during page load. The order of the HTML elements and the inline script is important here. The startCopy function must be called before the startAwesomplete function, because the latter can immediately fire the 'awesomplete-prepop' event which should be handled by the former. The startCopy inline script should preferable be placed after the HTML element which is the target. If you do, it only has to lookup the target element once, but If you don't do this it will lookup the target element with each event.

If you use remote data loading and combine prepop:true with loadall:true the remote call will happen during page load. If prepop:false, the loadall will be done lazely, e.g. if the user makes changes and the input size >= minChars.

Country capitals
Example demonstrates:
  • One remote call (load all) resulting in one response list shared by multiple controls.
  • Copy related data of selected item to other input field, in two directions!
Enter either country or capital, and look what happens in the other field.
Input controls:

HTML

<input id="user_country" class="form-control" name="user[country]" type="text" >
  <input id="user_capital" class="form-control" name="user[capital]" type="text" >
Below the Awesomplete objects are created

Javascript

Seafood pizza toppings
Example demonstrates:
  • Data list in page source.
  • Select multiple items.
Enter for example 'Crayfish, Oysters'
Input control with data-list:

HTML

<input id="user_seafood" class="form-control" 
       name="user[seafood]" type="text" 
    data-list="Anchovies, Cajun Prawn, Crayfish, Lobster,
               Oysters, Prawns, Salmon, Shrimps,
               Smoked Salmon, Squid, Tuna, Whitebait">
Notice that you can enter multiple toppings, seperated by , or ;

Javascript

The regular expressions are used to extract the last part of the input from the rest.
Email address
Example demonstrates:
  • In the shown suggestions the email address is shown below the name. The value contains both.
  • Multiple input values.
Enter an email address (they are all from starwars.com):
Input control:

HTML

<input id="user_multimail" class="form-control"
       name="user[multimail]" type="text" >
This example uses Star Wars names from a github repository. The names2contacts function below constructs email addresses and a value that contains both name and email address.

Javascript

In this example the 'value' field contains both name and email address. By default only the matching text in the first line of the label is highlighted. The itemMarkAll function highlights all matching text in the suggestion list. Try for example to search on '@starwars.com' to see what it highlights with or without this function.

Javascript

The regular expressions are used to extract the last part of the input from the rest.
Dismissible chip pills
Example demonstrates:
  • Data list in page source.
  • Dismissible chip pills, rendered via template.
Enter for example 'Oysters'
This example has a lot of custom code. The hidden input with id user_seafood2_all is used to store the complete list. The visible input with id user_seafood2 is used to add new chip pills.

HTML

<input id="user_seafood2" class="form-control" 
       name="user[seafood2]" type="text" 
    data-list="Anchovies, Cajun Prawn, Crayfish, Lobster,
               Oysters, Prawns, Salmon, Shrimps,
               Smoked Salmon, Squid, Tuna, Whitebait" >

<input type="hidden" id="user_seafood2_all" value="" >

Javascript

Diacritics and ligatures
Example demonstrates:
  • Type base characters and get suggustions with diacritics and ligatures
This example allows you to search for words with diacritics by typing just the base characters. For example search for 'oss' and besides 'fossilien' you will get the suggestion of 'größe'.
  • o is base character of ö
  • The ligature ß can be searched with 'ss'
Input control:

HTML

<input id="user_diacritics" class="form-control"
       name="user[diacritics]" type="text" 
       data-list="ænigma, Æthel, böse, fließen, fossilien, fröhlich
       , führen, füllen, gänse, götter, größe, hände, hölle, hügel
       , küssen, kräftig, lösen, löwe, mädchen, männer, mächtig
       , müde, möglichkeit, Œdipus, œuvre, Osnabrück, rätseln
       , rösten, rühren, säen, säubern, schön, schwül, STRAUß
       , süß, träumen, überlegen, übermäßig, vögel, wählen, wände
       , IJmuiden, zählen, accès, appétit, cliché, déjà vu, garçon
       , hôtel, île, accès, maître, pâté, où, quête, tête-à-tête
       , voilà" >
The functions below are used to convert diacrites and ligatures to base characters.

Javascript

In the code below the filter function replaces diacritics and ligatures in both the search phrase and the suggestions from the lists. After the conversions the strings with base characters can be compared.

Javascript

This example uses a fixed list of words. If you use a backend service to get suggestions, this backend service must apply the same search algorithm as this filter.

Installation & CSS style

Installation

In the header of your HTML page add:

HTML

<link rel="stylesheet" href="https://nico-amsterdam.github.io/awesomplete-util/css/awesomplete.css">
  <script src="https://nico-amsterdam.github.io/awesomplete-util/js/awesomplete.min.js"></script>
  <script src="https://nico-amsterdam.github.io/awesomplete-util/js/awesomplete-util.min.js"></script>
  <style>
    div.awesomplete { display: block }

    div.awesomplete ul li p { display: block; font-size: small; margin-left: 1em }

    div.awesomplete .awe-found { border: 2px solid green }

    .hide-not-found div.awesomplete .awe-not-found { border-color: lightblue }

    div.awesomplete .awe-not-found { border: 2px solid red }

    .dropdown-btn .caron { border: 3px solid transparent; pointer-events: none }

  </style>
The awesomplete.css and awesomplete.min.js files are copied from Awesomplete and tested in combination with AwesompleteUtil. If you copy these files to your own project, do not forget to also copy the javascript sourcemaps (awesomplete.min.js.map and awesomplete-util.min.js.map).

CSS Style

Customize the above styling for your own needs. The CSS class 'awe-found' is put on the input control when the input exactly matches the value of an list item. The CSS class 'awe-not-found' is put on the input control when the list closes because there are no more matching items.

Events

Events triggered by Awesomplete. AwesompleteUtil adds these events:
Event name Description
awesomplete-loadcomplete Fired when a new list is assigned to Awesomplete after a succesful ajax call. The event detail property contains the input value that triggered the ajax call.
awesomplete-match Fired when a new input value is compared with the item list. The event detail property contains an array with the matching list item(s). The array is empty when there is no match.
awesomplete-prepop Fired when the initial/autofilled value is compared with the item list. The event detail property contains an array with the matching list item(s). The array is empty when there is no match.

API

Functions

Function name Description
ajax(url, urlEnd, val, fn, xhr) Default ajax method, available for convenience. It performs a GET request on url + val + urlEnd. fn is the callback method. xhr is optional, you can pass on a preconfigured XMLHttpRequest.
convertInput(text) Default convertInput available for convenience. It trims spaces and converts text to lowercase.
item(html, input) Item function (as specified in Awesomplete) which create an 'li' element with the given html as innerHTML.
itemContains(html, input) Item function (as specified in Awesomplete) that highlights occurrences of the input text in the first line (until <p>). This function is used by default.
itemMarkAll(html, input) Item function (as specified in Awesomplete) that highlights all occurrences of the input text.
itemStartsWith(html, input) Item function (as specified in Awesomplete) that highlights the input text in the start text.
load(awe, list, queryValue) Load a new list. queryValue is the value that was used to retrieve the list. Set to null if for any change a re-query must be done. Set to true if the list contains all values (loadall).
mark(text, input, startsWith) returns text with HTML mark elements for matching input. It does not place markers in HTML tags. When startsWith is true it only marks matching begin text.
itemStartsWith(text, input) item function (as specified in Awesomplete) which highlights matching begin text.
update(awe, value, prepop) Update awesomplete input value via javascript. If you do this directly on the input control, no events will fire. If you use this update function, the AwesompleteUtil can check if the value exists in the suggestion list and set classes on the input control and fire it's events. Specify prepop=true if it is an initial value (no user input). Default value for prepop: false
updateList(awe, queryResult, queryValue, forceUpdate) Replace the current list with suggestions with a new list. queryResult should contain an array or an object with an array or a JSON string. By default forceUpdate is false and it only replaces the list if the queryValue matches the current input value. If the list must be replaced this function will call the load function.
start(elemId, utilOpts, opts) Create the Awesomplete object and attach event-handlers for AwesompleteUtil. elemId must be either a DOM element or a string with the query for document.querySelector to find the element. In general use '#id_of_element'. utilsOpts is an JSON object with the options for AwesompleteUtil, see the table below. opts are the options for Awesomplete and are passed on unchanged.
startCopy(sourceId, dataField, targetId, prepop) Listens to awesomplete-prepop (when prepop is not false) and awesomplete-match events from the source, and copy the dataField to the DOM element with the given target id. The targetId can also be a javascript function. This function receives two parameters: event and dataField. The event detail property contains an array with the matching list item. The array is empty when there is no match. Default value for prepop: true. dataField must be null if the list items are strings.
startClick(btnId, awe) Listen to click events of a button. Toggles open/close of the suggestion list.
filterContains(data, input) filter function (as specified in Awesomplete) to filter suggestions. input is searched in data.value. Notice that Awesomplete.FILTER_CONTAINS by default searches on data.label.
filterStartsWith(data, input) filter function (as specified in Awesomplete) to filter suggestions. input is searched as start text in data.value. Notice that Awesomplete.FILTER_STARTWITH by default searches on data.label.
jsonFlatten(data) function to flatten JSON. Notice that you can supply extra options via jsonFlatten.bind(opts) where opts is a JSON object with options 'root', 'value' and 'label'.

Util options of the start function

Option name Description
ajax Replace ajax function. Supplied function receives these parameters: (url, urlEnd, val, fn, xhr). fn is the callback function. Default: AwesompleteUtil.ajax.
convertInput Convert input function. Internally convert input for comparison with the data list items. By default it trims the input and converts it to lowercase for a case-insensitive comparison.
convertResponse Convert JSON response from ajax calls. This function is called with the parsed JSON, and allows conversion of the data before further processing. Default: nil - no conversion.
debounce number. Time in milliseconds to wait for additional user input before doing the ajax call to retrieve suggestions. It limits the rate at which the JSON service is called per user session.
limit number. If a limit is specified, and the number of items returned by the server is equal or more as this limit, the AwesompleteUtil code assumes that there are more results, so it will re-query if more characters are typed to get more refined results. The limit:1 tells that not more than 1 result is expected, so the JSON service doesn’t have to return an array. With limit:0 it will always re-query if more characters are typed and the result doesn't have to be an array either. Limit:-1 will always requery and the expected result is an array. When no limit is specified, the code assumes that all possible suggestions are returned based on the typed characters, and it will not re-query if more characters are typed. It uses the specified filter for the suggestions in the dropdown. Default: no limit
loadall true/false. true if the data list contains all items. The input value will not be used in ajax calls. Default: false
prepop true/false. If true do lookup initial/autofilled value and send awesomplete-prepop event. Default: false
url url for ajax calls.
urlEnd Addition at the end of the url of the ajax call, after the input value.

Anything else that comes to mind