Skip to content

Instantly share code, notes, and snippets.

@cbmeeks
Created November 30, 2023 01:35
Show Gist options
  • Select an option

  • Save cbmeeks/8b77df6a3077365c88b11b8b4e085a15 to your computer and use it in GitHub Desktop.

Select an option

Save cbmeeks/8b77df6a3077365c88b11b8b4e085a15 to your computer and use it in GitHub Desktop.

Revisions

  1. cbmeeks created this gist Nov 30, 2023.
    88 changes: 88 additions & 0 deletions custom.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,88 @@
    const autocomplete = (inputId, listId, dimensionCode) => {
    const input = document.getElementById(inputId)
    const list = document.getElementById(listId)
    if (!input || !list) return false
    list.innerHTML = ''

    let items = []
    let current = -1
    const bg_default = 'bg-white'
    const bg_select = 'bg-blue-500'
    const txt_default = 'text-black'
    const txt_select = 'text-white'

    // fetch all codes for the given dimension
    fetch(`/dimensions/${dimensionCode}`)
    .then(response => response.json())
    .then(data => items = data.sort())

    input.addEventListener('keydown', (e) => {
    const key = e.key
    const children = list.children
    if (!children) return false
    list.classList.remove('hidden')
    if (key === 'ArrowDown' || key === 'ArrowUp' || key === 'Enter') removeAllActives(children)
    if (key === 'ArrowDown') {
    if (current < children.length - 1) current += 1
    updateList()
    } else if (key === 'ArrowUp') {
    if (current > 0) current -= 1
    } else if (key === 'Enter') {
    e.preventDefault()
    input.value = children[current].value
    list.classList.add('hidden')
    current = -1
    } else if (key === 'Tab') {
    list.classList.add('hidden')
    }
    setActive(children, current)
    })

    input.addEventListener('input', (e) => {
    updateList()
    })

    input.addEventListener('change', (e) => {
    let valid = false
    for (let i = 0; i < items.length; i++) {
    if (items[i].code.trim().toLowerCase() === input.value.trim().toLowerCase()) {
    valid = true
    }
    }
    if (!valid) input.value = ''
    })

    function updateList() {
    list.innerHTML = ''
    let filtered
    input.value.trim() === '' ? filtered = items : filtered = items.filter((item) => item.name.toLowerCase().includes(input.value.toLowerCase()))
    filtered.forEach((item) => {
    const opt = document.createElement('option')
    opt.innerText = `${item.name} - ${item.code}`
    opt.value = item.code
    opt.onclick = () => {
    input.value = item.code
    list.classList.add('hidden')
    }
    list.appendChild(opt)
    })
    }

    function removeAllActives(children) {
    if (!children) return false
    for (let i = 0; i < children.length; i++) {
    children[i].classList.remove(bg_select, txt_select)
    children[i].classList.add(bg_default, txt_default)
    }
    }

    function setActive(children, index) {
    if (!children || index === undefined || index < 0) return false
    if (index > children.length - 1) return false
    children[index].classList.add(bg_select, txt_select)
    children[index].classList.remove(bg_default, txt_default)
    children[index].scrollIntoView({block: 'nearest'})
    }
    }

    autocomplete('newBranch', 'branch-list', 'branch')
    12 changes: 12 additions & 0 deletions example.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    <!-- Requires TailwindCSS -->

    <!-- Branch -->
    <div class="relative">
    <input type="text" id="newBranch" name="branch" autocomplete="off" placeholder="Branch"
    class="w-32 peer placeholder-transparent searchinput"/>
    <label for="newBranch" class="peerLabel">Branch</label>
    <ul id="branch-list"
    class="absolute top-9 left-0 bg-white w-64 max-h-64 z-50
    border border-gray-800 p-1 rounded-b-lg shadow-lg overflow-y-auto
    [&>option]:p-2 [&>option:hover]:bg-blue-500 [&>option:hover]:text-white hidden"></ul>
    </div>