Autocomplete

stablev2.0.0

Add autocomplete to text input elements, allowing the user to choose from a list of suggestions based on what he types in.

Overview

The autocomplete functionality is recommended for inputs when there is a lot of possible values to choose from.

Usage

Dependencies

To get the autocomplete component working, include the dependencies in your project in the following order:

  1. npm
  2. Sass
  3. JS
"design-system": "git+ssh://git@github.com/Selectra-Dev/design-system.git"
@import "design-system/src/scss/01-atoms/form.scss";
@import "design-system/src/scss/01-atoms/autocomplete.scss";
import Autocomplete from 'design-system/src/js/01-atoms/autocomplete';

Basic code

An autocomplete is composed by an input and it must be initialized with JS.

  1. HTML
  2. Pug
  3. JS
<input type="text" id="basic-autocomplete" />
input#basic-autocomplete(type='text')
new Autocomplete({
  selector: '#basic-autocomplete',
  urlToFetch: 'https://restcountries.eu/rest/v2/name/{param}'
});

In depth

Example

馃攳 Note: The Rest countries API is used for all the examples in this document. Please, check the response example to better understand the code.

In this example we are going to use all the features of the autocomplete.

Requirements:

  1. It has to show a list of countries.
  2. The suggestion should show the name of the country, and the continent for this country in between parentheses.
  3. The input has to match the beginning of the country name.
  4. The suggestion list has to be alphabetically ordered.
  5. Upon selection the input element value has to be set to the name of the country.
  6. Upon selection an alert box has to be shown, to inform the user of the geographical coordinates of this country.

We'll be using all four callback functions to illustrate how we can accomplish all these features.

There's a bunch of console.warn calls in the code for this example to log the input & output of each callback to the console.

They are there just so you can understand the flow of the data with ease, so... Open the console and do some tests!

new AutoComplete({
  selector: '#complex-autocomplete',
  apiUrl: 'https://restcountries.eu/rest/v2/name/{param}',


  // First we filter all the response data.
  //   1. We return a new Array with the properties we are interested.
  //   2. We filter out the datum whose name property do not begin with the
  //      input string.
  //   3. We sort the objects alphabetically, using the name property.

  processData: ( data, input ) => {
    const
      regexp = new RegExp( `^${ input }`, 'i' ),
      retVal = data.map( datum => {
          return {
            name: datum.name,
            region: datum.region,
            latLng: datum.latlng,
          };
        })
        .filter( datum => {
          return datum.name.match( regexp );
        })
        .sort(( a, b ) => {
          const
            nameA = a.name.toUpperCase(),
            nameB = b.name.toUpperCase();
          if ( a < b ) {
            return -1;
          } else if ( a > b ) {
            return 1;
          }
          return 0;
        });

    console.warn({
      processData: {
        input: { data: data, input: input },
        output: retVal,
      }
    });

    return retVal;
  },


  // We compose the string for each one of the suggestions list elements
  // with this callback.

  processDatumForDisplay: datum => {
    const retVal = `${ datum.name } (${ datum.region })`;
    console.warn({
      processDatumForDisplay: {
        input: { datum: datum },
        output: retVal,
      }
    });
    return retVal;
  },


  // We return the value for the input element value from this callback.

  processDatumForValue: datum => {
    const retVal = datum.name;
    console.warn({
      processDatumForValue: {
        input: { datum: datum },
        output: retVal,
      }
    });
    return datum.name;
  },


  // Finally, this callback will show the alert box with the selected
  // country coordinates.

  onSelectedResult: datum => {
    console.warn({
      onSelectedResult: {
        input: { datum: datum },
        output: null,
      }
    });
    const
      place = datum.name,
      lat = datum.latLng[ 0 ].toFixed( 3 ),
      latBearing = lat >= 0 ? 'N' : 'S',
      long = datum.latLng[ 1 ].toFixed( 3 ),
      longBearing = long >= 0 ? 'E' : 'W',
      latString = `${ Math.abs( lat ) }潞 ${ latBearing }`,
      longString = `${ Math.abs( long ) }潞 ${ longBearing }`;
    alert(
      `${ place } coordinates:\n[ ${ latString } - ${ longString } ]`
    );
  },
});

// That's all folks!

Options object

Find the list of options available to configure the autocomplete.

Property Type Default Required Description
selector String / Yes CSS selector of the input element for which we want to enable the autocomplete functionality.
apiUrl String / Yes The URL for the API that will be called upon user input.
It must include a substring {param} that will be replaced by the user input before making the request to the API.
The parsed JSON from the API response is expected to be an Array.
fetchInit Object {} No Optional custom settings for the request.
Check the MDN docs.
minChar Integer 1 No The minimum number of characters that need to be inputted before requests to the API are made.
limit Number Infinity No The maximum number of suggestions to show in the results list.
noScroll Boolean false No Disables scrolling on the results list if true
debounceTime Integer 350 No Calls to the API are debounced: Only the last call performed during this time window (expressed in milliseconds) will be actually performed.
processData Function undefined No Callback to process the whole JSON data from the response.
// Two arguments will be passed to this function:
//   路 data {Array} : The parsed JSON from the API response.
//   路 inputValue {String}: The user input.

( data, userInput ) => {
  // It's expected for this function to return an array.
  return data.map( datum => { datum.name, datum.capital );
}
processDatumForDisplay Function datum => datum No Either the parsed JSON data or the array returned from the processData callback will be iterated over, applying this callback to each of its elements.
The returned string will be used as the content of the recommendations list item for this datum.
// Two arguments will be passed to this function:
//   路 data {Array} : The parsed JSON from the API response.
//   路 inputValue {String}: The user input.

datum => {
  // Expected for this function to return a String.
  return datum.name;
}
processDatumForValue Function datum => datum No Callback to process the datum associated to the selected suggestion.
The returned value will be assigned to the input element value property.
// Two arguments will be passed to this function:
//   路 data {Array} : The parsed JSON from the API response.
//   路 inputValue {String}: The user input.

datum => {
  return datum.capital;
}
onSelectedResult Function undefined No Callback to execute when a suggestion is selected.
The datum associated to the selected suggestion is passed as an argument.
// One argument will be passed to this function:
//   路 datum {*} :The datum associated to the selected suggestion.

datum => {
  alert(
    `The capital of ${ datum.name } is { datum.capital }`
  );
}