Typeahead

Github https://github.com/Glagan/typeahead

Simple example Github

Using the default click event and add element function

Custom example Github

Using a custom add element function and click event function

Using the French public location API.

{
    "attribution": "BAN",
    "limit": 5,
    "type": "FeatureCollection",
    "licence": "ODbL 1.0",
    "query": "test",
    "version": "draft",
    "features": [{
        "type": "Feature",
        "geometry": {
            "type": "Point",
            "coordinates": [2.048421, 44.371337]
        },
        "properties": {
            "id": "12300_B258_cccc62",
            "citycode": "12300",
            "score": 0.8334454545454545,
            "x": 624176.5,
            "postcode": "12200",
            "importance": 0.1679,
            "y": 6364046.0,
            "context": "12, Aveyron, Occitanie (Midi-Pyr\u00e9n\u00e9es)",
            "label": "Testes 12200 Villefranche-de-Rouergue",
            "city": "Villefranche-de-Rouergue",
            "type": "street",
            "name": "Testes"
        }
    }, {
        "type": "Feature",
        "geometry": {
            "type": "Point",
            "coordinates": [0.357625, 43.950062]
        },
        "properties": {
            "id": "32107_XXXX_4964fb",
            "citycode": "32107",
            "score": 0.8278363636363636,
            "x": 487919.1,
            "postcode": "32100",
            "importance": 0.1062,
            "y": 6320333.2,
            "context": "32, Gers, Occitanie (Midi-Pyr\u00e9n\u00e9es)",
            "label": "Teste 32100 Condom",
            "city": "Condom",
            "type": "locality",
            "name": "Teste"
        }
    }]
}

Typeahead options

Here are the default options and their names:

{
    maxResults: 10,
    minLength: 3,
    delay: 200,
    listClasses: 'dropdown-menu',
    elementClasses: 'dropdown-item',
    activeClass: 'active',
    method: 'append',
    buildKey: this.node.name || 'q',
    otherParameters: {},
    encodeQuery: false,
    subKeys: [],
    resultKeys: ['name'],
    jsonResponse: true,
    onClickElement: null,
    onAddElement: null,
    onPreFetch: null,
    onPostFetch: null
}

maxResults

Maximum number of results added and displayed on the result list.

minLength

Minimum length of the string inside the input node before trying to request data and display results.

delay

Delay in milliseconds between each requests.

listClasses

All class names added to the result list node, the node that will contain all results nodes.
The classes are set using listNode.className = listClasses.

elementClasses

All class names added to each result node.
The classes are set using resultNode.className = listClasses.

activeClass

One class name that is added to the active element when navigating in the displayed results using the arrow keys.
The class is set using resultNode.classList.add(activeClass).

method

The value can be either append or build.

append

Using the append method make URLs where the parameters are separated using slashes, and the query will be appended at the end.

fetch('/test/sub/folder/{query}');

build

Using the build method will append the parameters at the end of the ressource as GET parameters.

fetch('/test?key=testKey&q{query}');

buildKey

This parameter is only used when the method is build.

Name of the key of the key/value pair that will contain the query value.

fetch('/test?{buildKey}={query}');

otherParameters

If you have other parameters to send when sending the query, you can set an object where the key/value pair of each properties will be appended to the URL of the ressource.
The method of adding other parameters is different depending on your method option.

method: build

When using the build method, the other parameters are simply appended as others GET parameters.

{
    method: 'build',
    otherParameters: {
        key: '99f5ac3d'
    }
}
// with a query of "example" on "/test" the fetch will be like that:
fetch('/test?q=example&key=99f5ac3d');

method: append

When using the append method, the other parameters can be appended with a value or not, or added as GET parameters.

The query (value of the input) is always appended at the end.

{
    method: 'append',
    otherParameters: {
        authors: '', // <- added as "/authors"
        deep: 'ocean', // <- added as "/deep/ocean"
        key: 'GET_99f5ac3d', // <- added as "?key=99f5ac3d"
        page: 'GET_1' // <- added as "&page=1"
    }
}
// with a query of "example" on "/test" the fetch will be like that:
fetch('/test/authors/deep/ocean/example?key=99f5ac3d&page=1');

encodeQuery

Use the encodeURIComponent function on every parameters before sending the request.

subKeys

If the result list is not the response itself, you need to set the subKeys option, it will be used to retrieve the array used to display the results.

// Example of response, with the real result list under the 'result' key
let response = {
    info: 'ok',
    code: 200,
    result: [ // <-- we need to use that array "response.result"
        'nice', 'ecin'
    ];
};
// And the options you need to set to catch the results
let options = {
    subKeys: ['result']
};

resultKeys

You can pass an array of strings, or an array of Objects to Typeahead.
When passing an array of Objects, the resultKeys option is used and the data displayed will be accessed with the keys used in chain.

// Example of nested result
let response = {
    code: 200,
    results: [ // <- first subKey
        {
            id: 1,
            properties: { // <- first resultKey
                name: 'ecin', // <- second resultKey
                fact: true
            }
        }, // ...
    ]
};
// You need to set options like that:
let options = {
    subKeys: ['results'],
    resultKeys: ['properties', 'name']
}

jsonResponse

Set to true, the result will be parsed as JSON, set to false, the result will be returned as plain text, as it was received by the browser.
This option is useful if you receive XML data for example, you can set the onPostFetch function to parse it (using your own functions) and return the result you parsed.

Functions on events

There is 4 functions that you can customize and that are called before, after or to replace an event.
The scope of those functions is always set to the scope of your Typeahead object (to use the this variable).

onAddElement

This function will be called on each result of the results array (or object).

{
    onAddElement: function(resultNode, newElementNode, element, index) {
        // Do what you want here
    }
}
Parameter name Description
resultNode UL node that contain each results.
newElementNode LI node of the result that would usually be appended as a child to resultNode.
element Value of the current result in the array.
index The index on the results array of the current element.

⚠️ If this parameter is set, element will contain the result as it is received, the resultKeys option will NOT be used.
However, the resultKeys option will still be used when moving between results with arrow keys, since the final input can only be a string.
The node newElementNode will have NO EVENTS, you can add one easily using one of the two functions available:

// inside the onAddElement you're defining
function(resultNode, newElementNode, element, index) {
    // Reminder: this scope is inside your Typeahead object
    this.addCustomOnClickElement(newElementNode, element);
    // Or if you wish to have the default behavior
    this.addDefaultOnClickElement(newElementNode, element);
}

addCustomOnClickElement will add the onClickElement option if it's defined, or else it will add the default click event, using addDefaultOnClickElement(newElementNode, elementValue).

onClickElement

When you set this function, it could be added as a click event to each result node in the result list.
could because you can avoid setting it when you're using a custom onAddElement, using addDefaultOnClickElement instead of addCustomOnClickElement.

{
    onClickElement: function(element, event) {
        // Do what you want here
    }
}
Parameter name Description
element Value of the result, it could be a string, or anything else if you are using the onAddElement option.
event Event object of the click, emitted by the browser.

⚠️ This value is null by default if there is no event, when the selection is done using the arrow keys.

You can still use the default click event behavior by using the defaultOnClickElement(elementValue) function that take a string as a parameter inside your onClickElement.
The default function save the current input, then set the input value as the clicked element value and hide the results list.

onPreFetch

Called before the lookup request is fetch, after checking if a request can be send.

{
    onPreFetch: function(query, currentTime) {
        // Do what you want here
    }
}
Parameter name Description
query string that is appended in the URL of the ressource
currentTime Current time (for example 1538666134372) in milliseconds used to check if the request could be send.

onPostFetch

Function called after the lookup request has been fetched, and after it was parsed from JSON, or simply returned as plain text if jsonResult is set to false.

{
    onPostFetch: function(response) {
        // Do what you want here
    }
}
Parameter name Description
response The responses received as it is from the browser.

⚠️ If you set this parameter, you NEED to return an array of string or objects, you can simply return response if you don't need or want to do anything.