vol1ura/Sat_9am_5km

View on GitHub
app/javascript/controllers/autocomplete_controller.js

Summary

Maintainability
A
1 hr
Test Coverage
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static values = { url: String }
  static targets = ['input', 'hidden', 'results']
  static timeout = null

  search(event) {
    if (this.inputTarget.value.length < 3) {
      this.closeAutoComplete()
      return
    }
    this.handle_choice(event)
  }

  select(event) {
    this.selectAthlete(event.target)
  }

  handle_choice(event) {
    const current_choice = this.resultsTarget.querySelector('li.active')
    if (event.which == 40) {
      const next_item = current_choice ? current_choice.nextElementSibling : this.resultsTarget.querySelector('li:first-child')
      if (next_item) {
        next_item.classList.add('active')
        current_choice?.classList.remove('active')
      }
    } else if (event.which == 38) {
      if (!current_choice) return
      current_choice.previousElementSibling?.classList.add('active')
      current_choice.classList.remove('active')
    } else if (event.which == 13) {
      event.preventDefault()
      if (current_choice) this.selectAthlete(current_choice)
    } else if (event.which == 27) {
      this.closeAutoComplete()
    } else {
      this.handle_search()
    }
  }

  handle_search() {
    clearTimeout(this.timeout)
    this.timeout = setTimeout(() => {
      fetch(`${this.urlValue}?q=${this.inputTarget.value}`)
        .then(response => response.json())
        .then(data => this.fillDropDown(data.athletes))
    }, 350)
  }

  fillDropDown(athletes) {
    this.resultsTarget.innerHTML = ''
    athletes.forEach((athlete, i) => {
      if (i >= 10) return
      const home_event = athlete.home_event ? ` (${athlete.home_event})` : ''
      const list_item = `<li class="list-group-item" athlete_id="${athlete.id}" name="${athlete.name}"><span class="badge bg-secondary">A${athlete.code}</span> ${athlete.name}${home_event}</li>`
      this.resultsTarget.insertAdjacentHTML('beforeend', list_item)
    })
  }

  closeAutoComplete() {
    this.resultsTarget.innerHTML = ''
  }

  selectAthlete(item) {
    this.hiddenTarget.value = item.getAttribute('athlete_id')
    this.inputTarget.value = item.getAttribute('name')
    this.closeAutoComplete()
  }
}