Getting data attributes from HTML input element with a datalist

38 Views Asked by At

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) {
    }
}
0

There are 0 best solutions below