User Live Search with Stimulus, Turbo Frames and PgSearch

Curated ago by @jeremysmithco

Description

Here’s a solution I’ve used on a project to add a user switcher dropdown with typeahead search to a navbar. It uses the pg_search gem for Postgres full-text search.

There are a lot of blog posts out there with similar solutions, with terms like: typeahead, autocomplete, autosuggest, instant search.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { Controller } from '@hotwired/stimulus';
import debounce from 'lodash.debounce';

export default class extends Controller {
  static targets = ['form', 'query', 'loading', 'results'];
  static classes = ['hide'];

  initialize() {
    this.search = debounce(this.search, 200).bind(this);
  }

  process() {
    if (this.queryTarget.value == '' || this.queryTarget.value.trim().length >= this.minCharacters) {
      this.loading();
      this.search();
    }
  }

  loading() {
    this.hide(this.resultsTarget);
    this.show(this.loadingTarget);
  }

  search() {
    this.formTarget.requestSubmit();
  }

  show(target) {
    target.classList.remove(this.hideClass);
  }

  hide(target) {
    target.classList.add(this.hideClass);
  }

  get minCharacters() {
    return 2;
  }
}

The live search controller uses debounce to limit requests to every 200ms. The process() function ensures that the search will not fire if the input is empty or 2 characters or less.