1

I'm working on extending the input element to use the nice datalist autocomplete functionality, but restrict only to the elements in the datalist, much like a select. Problem is I need the data attributes from the options in the datalist.

The search brings up a lot of failed attempts, including this one with an accepted answer that seems to imply you get get the data attributes from the input element, but that's not the case in my testing. The best I've found is getting the value of the input on 'insertReplacementText' and searching the associated dataset, but I was wondering if there's a more straightforward solution.

That also doesn't work with duplicate dataset values, but I can force them to be unique if that's my only choice.

Here's my test code:

<script>
    class MyInputListElement extends HTMLInputElement {
        constructor() {
            // Always call super first in constructor
            self = super();
        }

        connectedCallback() {
            // Dump everything for testing
            for (let o of this.list.options)
            {
                for (let d in o.dataset)
                {
                    console.log(o.value + ": " + d + " " + o.dataset[d]);
                }
            }
            this.addEventListener('change', () => {
                console.log("change: " + this.dataset);
                for (let d in this.dataset)
                {
                    console.log(d + " " + this.dataset[d]);
                }
            });
            this.addEventListener('input', () => {
                console.log("input: " + this.dataset)
                for (let d in this.dataset)
                {
                    console.log(d + " " + this.dataset[d]);
                }
            });
        }
        
        attriuteChangedCallback(name, oldValue, newValue) {
        }
    }
    customElements.define("my-list-input", MyInputListElement, {extends: "input"});
</script>

<datalist id="ice">
    <option value="Chocolate" data-test1="chicken" data-test2="parm"></option>
    <option value="Coconut"></option>
    <option value="Mint"></option>
    <option value="Strawberry"></option>
    <option value="Vanilla"></option>
</datalist>
<input is="my-list-input" list="ice" id="mylist">

Output after clicking in the input box and selecting Chocolate:

Chocolate: test1 chicken test.php:86:14
Chocolate: test2 parm test.php:86:14
input: [object DOMStringMap] test.php:97:13
change: [object DOMStringMap] test.php:90:13

I was wondering if we could hook into the selection box that pops up when you click the input box, but I don't see it appear in the DOM.

Has anyone figured this out yet in 2024 or is a value search through the datalist still the only way?

Edit: just for completeness, here's a working implementation of the lookup method. This makes it work very much like a select, but with the dataset style typing ahead.

class MyInputListElement extends HTMLInputElement {
    constructor() {
        // Always call super first in constructor
        self = super();
        this.curSel = '';
    }

    connectedCallback() {
    this.addEventListener('change', () => {
        this.value = this.curSel;
    });
    
    this.addEventListener('input', (e) => {             
        if (event.inputType === 'insertReplacementText')
        {
            // This means the user selected a value, so set it as our
            // current selection to fall back on if they navigate away
            this.curSel = this.value;
            
            // Now find a matching datalist item and grab its dataset
            for (let opt of this.list.options) {
                if (opt.value === this.value) {
                    // Got 'em. Now clear our dataset and add the option's
                    for (let d in this.dataset) {
                        delete this.dataset[d];
                    }
                    for (let d in opt.dataset) {
                        this.dataset[d] = opt.dataset[d];
                    }
                    
                    break;
                }
            }
            console.log(this.dataset);
        }
    });
}

    attriuteChangedCallback(name, oldValue, newValue) {
    }
}
4
  • You're referencing this.dataset, but this seems to be the input, which doesn't have any data- attributes. Curious: why did you choose a datalist instead of a select? Commented Mar 29, 2024 at 18:59
  • @mykaf: first because of the nice autocomplete type-ahead functionality. Second because I have a large-ish list of options that may have to appear in many selects. It'd be really nice if I could have those options live in one place in the HTML instead of duplicated for every select. Commented Mar 29, 2024 at 19:05
  • Maybe this would help? stackoverflow.com/questions/58521557/… Seems like you have to use the input's value to get back to the datalist option. Commented Mar 29, 2024 at 19:17
  • Thank you @mykaf. Looks like that answer does the same thing my code does, but with selectors instead of a for loop. Commented Mar 29, 2024 at 19:21

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.