Autocomplete in RxJS (code walk)


Autocomplete functionality is probably the first use case you hear for using RxJS. Here is one possible implementation for it (code can be also found in JSBin):

let input = document.querySelector('input')
let inputStream = Rx.Observable.fromEvent(input, 'input')

let ul = document.querySelector('ul')

let responseStream = inputStream
  .debounceTime(500)
  .map(e => e.target.value)
  .filter(value => !value | value.length > 2)
  .distinctUntilChanged()
  .flatMap(
    value => value ? Rx.Observable.fromPromise(axios.get(`/states?q=${value}`)) : Rx.Observable.of({data: []})
  );

responseStream.subscribe(({ data }) => {
  ul.innerHTML = data.map(state => `<li>${state}</li>`).join('')
})
    In plain English, when user type into input field:

  1. we first wait that user finishes with typing (this happens when there is no new typing for some amount of time, say 500 ms).
  2. Secondly, we extract value from input.
  3. If value is not at least 3 characters long or empty, we ignore it and stop with the flow.
  4. Otherwise we compare its value and if it’s the same as the last time user finished typing, we ignore it and stop the flow since these values aren’t distinct. There is no point in abusing the server if result is already there.
  5. If distinct, we make the request. But only if value is not empty. If latter, we just return observable that emits object with empty data. Because again, no need for abusing the server if the output is known. Also if we wouldn’t have control over empty values than server would return all records. Which is not the desired effect.
  6. Lastly, we subscribe to the input observable and based on data generate list and attach it to DOM