7

I am tring to make datalist in html here is example

<h1>Datalist Demo</h1>
<label for="default">Pick a programming language</label>
<input type="text" id="default" list="languages">
<datalist id="languages">
    <option value="HTML">
    <option value="CSS">
    <option value="JavaScript">
    <option value="Java">
    <option value="Ruby And Go">
    <option value="PHP And HTML">
    <option value="Go">
    <option value="Erlang">
    <option value="Python And C++">
    <option value="C">
    <option value="C#">
    <option value="C++">
</datalist>

but when i search for 'go' it show me 2 results

  • Ruby And Go
  • Go

Result When i Search for 'go'

I want that it should only show term which match the beginning of entered text and NOT from inside.
Like When I search for 'go' only one result should be displayed

  • Go

I have to implement this on more than 5000 records stored in MySQL.

A Vyom
  • 105
  • 1
  • 8
  • 2
    I don't think its a good idea to have all 5000 records loaded in the datalist, I would suggest to go for auto-complete/type-ahead controls (lots of jQuery plugin's available) for this and hit the server to retrieve the records matching the rule you need. And for your question - http://stackoverflow.com/questions/29154877/use-html5-datalist-autocomplete-with-contains-approach-not-just-starts-wit - might help – Developer Mar 04 '17 at 06:49
  • 2
    Possible duplicate of [Use HTML5 (datalist) autocomplete with 'contains' approach, not just 'starts with'](http://stackoverflow.com/questions/29154877/use-html5-datalist-autocomplete-with-contains-approach-not-just-starts-wit). I know this is technically the *opposite* question, but the underlying desire for control over the `` behavior is the same. – gyre Mar 04 '17 at 06:54
  • I suggest you to use str.length method.For this example get the lenght of 'Ruby and Go' and the length of 'Go' and return only the Go.You must consider an a possible space entry before the word Go. – liontass Mar 04 '17 at 07:08

2 Answers2

4

There is a pretty sound solution for such situations: to leave an empty datalist inner html (if empty, it will be filled on a focus event) and fill it dynamically on every input event with Javascript. In JS, it is better to alphabetically sort the array of options to be able to stop iteration when some coincidences are already found and there's no further matches. Continuing the example of this question:

const dlOptions = ["C", "C#", "C++", "CSS", "Erlang", "Go", "HTML", "Java",
"JavaScript", "PHP And HTML", "Python And C++", "Ruby And Go"].map(o => {
    return [`<option value="${o}"></option>`, o.toLowerCase()];
});

function completeDataList(e) {
    const fill = val => document.getElementById('languages').innerHTML = val;
    if(!e.target.value) {
        fill(dlOptions.reduce((sum, [html]) => sum + html, ''));
    } else if(!(e instanceof InputEvent)) { // OR: else if(!e.inputType)
        e.target.blur();
    } else {
        const inputValue = e.target.value.toLowerCase();
        let result = '';
        for (const [html, valuePattern] of dlOptions) {
            if (!valuePattern.indexOf(inputValue)) {
                result += html;
            } else if (result) {
                break;
            }
        }
        fill(result);
    }
}

function fillDataListIfEmpty() {
    if(!document.getElementById('languages').innerHTML) {
        completeDataList({ target: {} });
    }
}
<h1>Datalist Demo</h1>
<label for="default">Pick a programming language</label>
<input type="text" id="default" list="languages" oninput="completeDataList(event)" onfocus="fillDataListIfEmpty()">
<datalist id="languages"></datalist>

P.S. Works like a charm on both desktop and mobile devices (I use this approach in my project, generating datalist on input out of ~80 options). However, as it was already mentioned above, for big quantities of options it is much more reasonable to resort to server solutions with database queries.

UPD: when using this approach, it should be noted that choosing a datalist option also triggers an input event (or, more precisely to say, just an instance of Event, but not of InputEvent), and, for the sake of good user experience, it should be taken into account (otherwise datalist options wrongly pop up again after choosing an option); the similar situation is with keyup event. I've just updated the code.

UPD2: I have edited the function completeDataList according to the advice of @heretic-monkey (for details see the comments under this post). Also, for the sake performance, the array of option values is converted to another array of static search and html patterns and initialized as a global variable (in order to use these patterns on each input event instead of rebuilding them multiple times on each of events), which is crucially important in cases with large quantity of options and/or frequent calls of the function.

Roman Karagodin
  • 740
  • 2
  • 11
  • 16
  • 1
    Why use regular expressions at all, and run the risk of invalid characters? Just use `option.indexOf(e.target.value) === 0` and that will tell you whether the value is at the start of the option or not. – Heretic Monkey Feb 02 '21 at 22:22
  • Thanks for advice! In my current solution, I handle potential syntax errors, caused by invalid regex patterns, in the catch block (see the code above). If to stick to your variant, it will need another operation of making the check case-insensitive (to recognize such input as, e.g., *JAVA*, *Java* and *java*) – something like `option.toLowerCase().indexOf(e.target.value.toLowerCase()) === 0`. Do you think that it will be as good in terms of performance as checking against a regexp? – Roman Karagodin Feb 02 '21 at 23:08
  • The post has been just edited with regard to the suggestion discussed above. – Roman Karagodin Feb 03 '21 at 12:39
-2

For exact matches you can set pattern attribute value dynamically to RegExp [\\w\\s+#]{${this.value.length}} at input event

<h1>Datalist Demo</h1>
<label for="default">Pick a programming language</label>
<input type="text" id="default" list="languages" pattern="">
<datalist id="languages">
    <option value="HTML">
    <option value="CSS">
    <option value="JavaScript">
    <option value="Java">
    <option value="Ruby And Go">
    <option value="PHP And HTML">
    <option value="Go">
    <option value="Erlang">
    <option value="Python And C++">
    <option value="C">
    <option value="C#">
    <option value="C++">
</datalist>
<script>
  document.querySelector("#default")
  .oninput = function() {
    this.pattern = `[\\w\\s+#]{${this.value.length}}`;
  }
</script>
guest271314
  • 1
  • 15
  • 104
  • 177