This is a light-weight JavaScript widget that provides autocomplete for freeform text inputs that get their suggestions from remote sources. One such example is address autocomplete. It has the following nice features:
- Handles fetching results via HTTP.
- Supports keyboard navigation.
- Customizable to support different data format.
- No dependencies and small in size.
Demo: http://danqing.github.io/autocomplete/
Get it from npm, or simply download the ac.js
file and put it into your project.
npm install remote-ac --save
var AC = require('remote-ac');
var ac = new AC(input, urlFn, requestFn, resultFn, rowFn, triggerFn, anchorEl);
where:
input
is the text field that holds the user input to autocomplete.urlFn
is the function that takes the user input string and returns the URL to retrieve the autocomplete results. It is assumed that it is a GET request.requestFn
is the function that allows full customization of a request behavior. It takes the user input string and should updatethis.results
with the desired result and callthis.render()
to update the autocomplete. If this function is provided, bothurlFn
andresultFn
will be ignored.resultFn
is the function that processes the returned results, in case you have some custom format. It takes the raw HTTP response, and returns a list of autocomplete results. If the response is already a list of results, you do not need to specify this function.rowFn
is the function that takes the data of a row to render the row in the DOM. If it is not provided, autocomplete will generate the rows automatically.triggerFn
is the function called when the user clicks on an autocomplete row. The result associated with the row will be passed in as the first parameter. The second parameter is the triggering event (click or keypress) so you can prevent event bubbling or process it in other ways.anchorEl
is the element to position the autocomplete against, in case you don't want it to be positioned below the input element.
If you would like to use the default row rendering function, you can have a primary text label and an optional secondary text label. The default keys to them are title
and subtitle
, i.e.:
[{
'title': 'Some Title Label',
'subtitle': 'Some Subtitle Label',
'other_key': '...'
}, {
...
}]
If your payload has some other keys, you can change the label keys with the following:
var ac = new AC(...);
ac.primaryTextKey = 'your_key';
ac.secondaryTextKey = 'your_secondary_key';
Full example (find it in the gh-pages branch):
var service = new google.maps.places.PlacesService(...);
// Custom request function.
var requestFn = function(query) {
if (!query) {
this.results = [];
this.render();
return;
}
service.textSearch({query: query}, (results, status) => {
this.results = [];
if (status === google.maps.places.PlacesServiceStatus.OK) {
this.results = results.length > 5 ? results.slice(0, 5) : results;
}
this.render();
});
};
var triggerFn = function(obj) {
var output = document.getElementById('output');
output.textContent = 'You selected ' + obj.name;
};
var input = document.getElementById('input');
var ac = new AC(input, null, requestFn, null, null, triggerFn);
// This is the key to get the primary text from.
ac.primaryTextKey = 'name';
// This is the key to get the secondary text from. If the key does not exist,
// it will be ignored.
ac.secondaryTextKey = 'formatted_address';
Three other configurations are available:
delay
is the delay after each keystroke before firing the XHR request, in milliseconds. Default is 300ms.minLength
is the minimum input length required before firing the XHR request. Default is 1. This only works with the defaultrequestFn
. If you supply a customrequestFn
, it will always be triggered and it is up to you to handle minimum length logic.cssPrefix
is the prefix added to each CSS class name, in case the default prefix conflicts, or you have multiple widgets with different styling. The default is 'ac-'.
They are not exposed as part of the constructor function, but can be set after the autocomplete object is created:
var ac = new AC(...);
ac.delay = 500;
ac.minLength = 3;
ac.cssPrefix = 'ac-secondary-widget-';
When the autocomplete is created, it's automatically activated, meaning that focusing on the input will trigger the autocomplete logic. You can call ac.deactivate()
to deactivate the autocomplete, and reactivate it with ac.activate()
.
The library comes with a default style for your reference. Start with it so the autocomplete is working, and then modify it to meet your UI requirements.
The following CSS classes are applied to the autocomplete DOM elements if you are using the default rendering system:
AC.CLASS = {
WRAPPER: 'ac-wrap',
ROW_WRAPPER: 'ac-rwrap',
ROW: 'ac-row',
SELECTED_ROW: 'ac-row selected',
PRIMARY_SPAN: 'ac-pr',
SECONDARY_SPAN: 'ac-sc',
MOBILE_INPUT: 'ac-minput',
CANCEL: 'ac-cancel'
};
The autocomplete library comes with two utility functions that you may find useful:
/**
* Turns a query dictionary into a HTML-escaped query string.
*
* @param {Object} obj The query dict such as {a: 'b', c: 'd'}.
* @return {string} The encoded query string such as a=b&c=d.
*/
AC.encodeQuery = function encode(obj);
/**
* Creates DOM elements for autocomplete result input highlighting. With the
* whitespaces in the input trimmed, the input will be in bold (b) whereas
* everything else will be left intact (span).
*
* @param {string} input The user input string.
* @param {string} complete The autocompleted string.
* @return {Fragment} The document fragment that contains the created DOM
* elements.
*/
AC.createMatchTextEls = function match(input, complete);
The first function may be useful when you construct your URL in the urlFn
. The second function may be useful if you have custom rendering logic but still want the keyword highlight.
MIT.