# Autocomplete.js This JavaScript library adds a fast and fully-featured auto-completion menu to your search box displaying results "as you type". It can easily be combined with Algolia's realtime search engine. The library is available as a jQuery plugin, an Angular.js directive or a standalone library. [](http://travis-ci.org/algolia/autocomplete.js) [](http://badge.fury.io/js/autocomplete.js) [](https://coveralls.io/r/algolia/autocomplete.js?branch=master) [](https://www.jsdelivr.com/package/npm/autocomplete.js)    [](https://opensource.org/licenses/MIT) [](https://saucelabs.com/u/opensauce-algolia) ## Table of Contents - [Features](#features) - [Installation](#installation) - [jsDelivr](#jsdelivr) - [cdnjs](#cdnjs) - [npm](#npm) - [Bower](#bower) - [Source dist/](#source-dist) - [Browserify](#browserify) - [Usage](#usage) - [Standalone](#standalone) - [jQuery](#jquery) - [Angular.JS](#angularjs) - [Look and Feel](#look-and-feel) - [Global Options](#global-options) - [Datasets](#datasets) - [Sources](#sources) - [Hits](#hits) - [PopularIn (aka "xxxxx in yyyyy")](#popularin-aka-xxxxx-in-yyyyy) - [Custom source](#custom-source) - [Security](#security) - [User-generated data: protecting against XSS](#user-generated-data-protecting-against-xss) - [FAQ](#faq) - [How can I `Control`-click on results and have them open in a new tab?](#how-can-i-control-click-on-results-and-have-them-open-in-a-new-tab) - [Events](#events) - [API](#api) - [jQuery](#jquery-1) - [Standalone](#standalone-1) - [Contributing & releasing](#contributing--releasing) - [Credits](#credits) ## Features * Displays suggestions to end-users as they type * Shows top suggestion as a hint (i.e. background text) * Supports custom templates to allow for UI flexibility * Works well with RTL languages and input method editors * Triggers custom events ## Installation The `autocomplete.js` library must be included **after** jQuery, Zepto or Angular.js (with jQuery). ### jsDelivr ```html ``` ### cdnjs ```html ``` ### npm ```sh npm install --save autocomplete.js ``` ### Bower ```sh bower install algolia-autocomplete.js -S ``` ### Source dist/ You can find the built version in [dist/](https://github.com/algolia/autocomplete.js/tree/master/dist). ### Browserify You can require it and use [Browserify](http://browserify.org/): ```js var autocomplete = require('autocomplete.js'); ``` ## Usage ### Standalone 1. Include `autocomplete.min.js` 1. Initialize the auto-completion menu calling the `autocomplete` function ```html ``` ### jQuery 1. Include `autocomplete.jquery.min.js` after including `jQuery` 1. Initialize the auto-completion menu calling the `autocomplete` jQuery plugin ```html ``` ### Angular.JS 1. Include `autocomplete.angular.min.js` after including `jQuery` & `Angular.js` 1. Inject the `algolia.autocomplete` module 1. Add the `autocomplete`, `aa-datasets` and the optional `aa-options` attribute to your search bar ```html
{{value}}
`. * `debounce` – If set, will postpone the source execution until after `debounce` milliseconds have elapsed since the last time it was invoked. * `cache` - If set to `false`, subsequent identical queries will always execute the source function for suggestions. Defaults to `true`. ## Sources A few helpers are provided by default to ease the creation of Algolia-based sources. ### Hits To build a source based on Algolia's `hits` array, just use: ```js { source: autocomplete.sources.hits(indexObj, { hitsPerPage: 2 }), templates: { suggestion: function(suggestion, answer) { // FIXME } } } ``` ### PopularIn (aka "xxxxx in yyyyy") To build an Amazon-like autocomplete menu, suggesting popular queries and for the most popular one displaying the associated categories, you can use the `popularIn` source: ```js { source: autocomplete.sources.popularIn(popularQueriesIndexObj, { hitsPerPage: 3 }, { source: 'sourceAttribute', // attribute of the `popularQueries` index use to query the `index` index index: productsIndexObj, // targeted index facets: 'facetedCategoryAttribute', // facet used to enrich the most popular query maxValuesPerFacet: 3 // maximum number of facets returned }, { includeAll: true, // should it include an extra "All department" suggestion allTitle: 'All departments' // the included category label }), templates: { suggestion: function(suggestion, answer) { var value = suggestion.sourceAttribute; if (suggestion.facet) { // this is the first suggestion // and it has been enriched with the matching facet value += ' in ' + suggestion.facet.value + ' (' + suggestion.facet.count + ')'; } return value; } } } ``` ### Custom source The `source` options can also take a function. It enables you to have more control of the results returned by Algolia search. The function `function(query, callback)` takes 2 parameters * `query: String`: the text typed in the autocomplete * `callback: Function`: the callback to call at the end of your processing with the array of suggestions ```js source: function(query, callback) { var index = client.initIndex('myindex'); index.search(query, { hitsPerPage: 1, facetFilters: 'category:mycat' }).then(function(answer) { callback(answer.hits); }, function() { callback([]); }); } ``` Or by reusing an existing source: ```js var hitsSource = autocomplete.sources.hits(index, { hitsPerPage: 5 }); source: function(query, callback) { hitsSource(query, function(suggestions) { // FIXME: Do stuff with the array of returned suggestions callback(suggestions); }); } ``` ## Security ### User-generated data: protecting against XSS Malicious users may attempt to engineer XSS attacks by storing HTML/JS in their data. It is important that user-generated data be properly escaped before using it in an *autocomplete.js* template. In order to easily do that, *autocomplete.js* provides you with a helper function escaping all HTML code but the highlighting tags: ```js templates: { suggestion: function(suggestion) { var val = suggestion._highlightResult.name.value; return autocomplete.escapeHighlightedString(val); } } ``` If you did specify custom highlighting pre/post tags, you can specify them as 2nd and 3rd parameter: ```js templates: { suggestion: function(suggestion) { var val = suggestion._highlightResult.name.value; return autocomplete.escapeHighlightedString(val, '', ''); } } ``` ## FAQ ### How can I `Control`-click on results and have them open in a new tab? You'll need to update your suggestion templates to make them as `` links and not simple divs. `Control`-clicking on them will trigger the default browser behavior and open suggestions in a new tab. To also support keyboard navigation, you'll need to listen to the `autocomplete:selected` event and change `window.location` to the destination URL. Note that you might need to check the value of `context.selectionMethod` in `autocomplete:selected` first. If it's equal to `click`, you should `return` early, otherwise your main window will **also** follow the link. Here is an example of how it would look like: ```javascript autocomplete(…).on('autocomplete:selected', function(event, suggestion, dataset, context) { // Do nothing on click, as the browser will already do it if (context.selectionMethod === 'click') { return; } // Change the page, for example, on other events window.location.assign(suggestion.url); }); ``` ## Events The autocomplete component triggers the following custom events. * `autocomplete:opened` – Triggered when the dropdown menu of the autocomplete is opened. * `autocomplete:shown` – Triggered when the dropdown menu of the autocomplete is shown (opened and non-empty). * `autocomplete:empty` – Triggered when all datasets are empty. * `autocomplete:closed` – Triggered when the dropdown menu of the autocomplete is closed. * `autocomplete:updated` – Triggered when a dataset is rendered. * `autocomplete:cursorchanged` – Triggered when the dropdown menu cursor is moved to a different suggestion. The event handler will be invoked with 3 arguments: the jQuery event object, the suggestion object, and the name of the dataset the suggestion belongs to. * `autocomplete:selected` – Triggered when a suggestion from the dropdown menu is selected. The event handler will be invoked with the following arguments: the jQuery event object, the suggestion object, the name of the dataset the suggestion belongs to and a `context` object. The `context` contains a `.selectionMethod` key that can be either `click`, `enterKey`, `tabKey` or `blur`, depending how the suggestion was selected. * `autocomplete:cursorremoved` – Triggered when the cursor leaves the selections or its current index is lower than 0 * `autocomplete:autocompleted` – Triggered when the query is autocompleted. Autocompleted means the query was changed to the hint. The event handler will be invoked with 3 arguments: the jQuery event object, the suggestion object, and the name of the dataset the suggestion belongs to. * `autocomplete:redrawn` – Triggered when `appendTo` is used and the wrapper is resized/repositionned. All custom events are triggered on the element initialized as the autocomplete. ## API ### jQuery Turns any `input[type="text"]` element into an auto-completion menu. `globalOptions` is an options hash that's used to configure the autocomplete to your liking. Refer to [Global Options](#global-options) for more info regarding the available configs. Subsequent arguments (`*datasets`), are individual option hashes for datasets. For more details regarding datasets, refer to [Datasets](#datasets). ``` $(selector).autocomplete(globalOptions, datasets) ``` Example: ```js $('.search-input').autocomplete({ minLength: 3 }, { name: 'my-dataset', source: mySource }); ``` #### jQuery#autocomplete('destroy') Removes the autocomplete functionality and reverts the `input` element back to its original state. ```js $('.search-input').autocomplete('destroy'); ``` #### jQuery#autocomplete('open') Opens the dropdown menu of the autocomplete. Note that being open does not mean that the menu is visible. The menu is only visible when it is open and has content. ```js $('.search-input').autocomplete('open'); ``` #### jQuery#autocomplete('close') Closes the dropdown menu of the autocomplete. ```js $('.search-input').autocomplete('close'); ``` #### jQuery#autocomplete('val') Returns the current value of the autocomplete. The value is the text the user has entered into the `input` element. ```js var myVal = $('.search-input').autocomplete('val'); ``` #### jQuery#autocomplete('val', val) Sets the value of the autocomplete. This should be used in place of `jQuery#val`. ```js $('.search-input').autocomplete('val', myVal); ``` #### jQuery.fn.autocomplete.noConflict() Returns a reference to the autocomplete plugin and reverts `jQuery.fn.autocomplete` to its previous value. Can be used to avoid naming collisions. ```js var autocomplete = jQuery.fn.autocomplete.noConflict(); jQuery.fn._autocomplete = autocomplete; ``` ### Standalone The standalone version API is similiar to jQuery's: ```js var search = autocomplete(containerSelector, globalOptions, datasets); ``` Example: ```js var search = autocomplete('#search', { hint: false }, [{ source: autocomplete.sources.hits(index, { hitsPerPage: 5 }) }]); search.autocomplete.open(); search.autocomplete.close(); search.autocomplete.getVal(); search.autocomplete.setVal('Hey Jude'); search.autocomplete.destroy(); search.autocomplete.getWrapper(); // since autocomplete.js wraps your input into another div, you can access that div ``` You can also pass a custom Typeahead instance in Autocomplete.js constructor: ```js var search = autocomplete('#search', { hint: false }, [{ ... }], new Typeahead({ ... })); ``` #### autocomplete.noConflict() Returns a reference to the autocomplete plugin and reverts `window.autocomplete` to its previous value. Can be used to avoid naming collisions. ```js var algoliaAutocomplete = autocomplete.noConflict(); ``` ## Contributing & releasing see [CONTRIBUTING.md](./CONTRIBUTING.md) ## Credits This library has originally been forked from [Twitter's typeahead.js](https://github.com/twitter/typeahead.js) library.