0

I am trying to create an autocomplete search box.
It works, but there is one problem here is that it won't start with the first letter when user type on the search box.
If I type the first letter on the search box, it will show all words contain this letter, but I only want it show words start with this letter.
What should I do? I found out this happen in firefox, but it is OK in chrome.

var dataList = document.getElementById("auto_json_datalist");
 // Create a new XMLHttpRequest.
var request = new XMLHttpRequest();
 // Handle state changes for the request.
request.onreadystatechange = function(response) {
  if (request.readyState === 4) {
    if (request.status === 200) {
      // Parse the JSON
      var jsonOptions = JSON.parse(request.responseText);
      // Loop over the JSON array.
      jsonOptions.forEach(function(item) {
        // Create a new <option> element.
        var option = document.createElement("option");
        // Set the value using the item in the JSON array.
        option.value = item;
        // Add the <option> element to the <datalist>.
        dataList.appendChild(option);
      });
    } else {
      // An error occured :(
    }
  }
};
 // Set up and make the request.
request.open("GET", "autocompleteSym.json", true);
request.send();
<datalist id="auto_json_datalist"></datalist>
<input type="text"  class="enter_sym_c" list="auto_json_datalist" value="" />
webdeb
  • 12,993
  • 5
  • 28
  • 44
conan
  • 1,327
  • 1
  • 12
  • 27

2 Answers2

0

Here, try to add these changes:

var SUCCESS_CODE = 200,
  NEEDED_REQUEST_STATE = 4,
  dataList = document.getElementById("auto_json_datalist"),
  enteredData = document.getElementsByClassName("enter_sym_c")[0],
  // the data entered by the user
  request = new XMLHttpRequest();

// Handle state changes for the request.
request.onreadystatechange = function(response) {
  if (request.readyState === NEEDED_REQUEST_STATE) {
    if (request.status === SUCCESS_CODE) {
      // Parse the JSON
      parseJSONOptions(request.responseText);
    } else {
      // An error occured :(
    }
  }
};

function parseJSONOptions(data) {
  var jsonOptions = JSON.parse(data);
  jsonOptions.forEach(function(item) {
    var itemString = new String(item["key"]); // you must know what is the key
    if (itemString.startsWith(enteredData.value)) {
      createOption(dataList, item);
    }
  });
}

function createOption(parent, value) {
  // Create a new <option> element.
  var option = document.createElement("option");
  // Set the value using the item in the JSON array.
  option.value = value;
  // Add the <option> element to the <datalist>.
  parent.appendChild(option);
}

// Set up and make the request.
request.open("GET", "autocompleteSym.json", true);
request.send();

You only need to take the string part that is already entered in the input and when you get the possible options - check each option, if it starts with the given substring and add it to the list, if this is true.

This solution covers also the cases for 2 characters, 3 characters etc.

victor175
  • 624
  • 3
  • 10
  • 23
  • 1
    You should explain what you did, so the OP actually knows what to do next time. – Adjit Jul 14 '16 at 21:37
  • 2
    I mean, the code is pretty self explanatory in this case. – Nicola Pedretti Jul 14 '16 at 21:50
  • Thanks for response, but i got error item.startsWith is not a function. – conan Jul 14 '16 at 22:02
  • In order for `startsWith` to work, the object must be a String, so you can make a string out of `item` in order to fix this. See my edit. – victor175 Jul 14 '16 at 22:07
  • it still the same error item.startsWith is not a function. – conan Jul 14 '16 at 22:14
  • Could you run the code, print `item` in the console and then share the output, by updating your answer? This is the only way to really tell what is the problem. – victor175 Jul 14 '16 at 22:16
  • `item` should be a JSON, you must know what is the key value and use my code. See the edits. – victor175 Jul 14 '16 at 22:26
  • if I use you code, my console gave this error: ReferenceError: item is not defined option.value = item; if I change the item to value, it doesn't give me any error, but It just won't autocomplete with first letter. – conan Jul 14 '16 at 22:38
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/117361/discussion-between-victor175-and-conan). – victor175 Jul 14 '16 at 22:52
  • Thanks for your time. I think I might give up this code since I just found out that datalist is not support in safari. This code is good at chrome. But I should find a better code that support safari and firefox. thanks again. – conan Jul 14 '16 at 23:12
0

This only requires a very simple if condition, that checks the first letter of the input value to see if it is equal to the first letter of the current item.
If this condition fails it will skip creating the option element.

This if condition looks like this:

if(inputBox.getAttribute("value").charAt(0) == item.charAt(0)) {}

The if condition gets the first letter of strings by using the String.prototype.charAt(...); function, and supplying 0 as the first (and only) argument.
If you don't know what String.prototype.charAt(...); is or you would like to know more about it you should read this MDN article.

The error item.charAt is not a function problem was caused because that the argument (function) inside jsonOptions.forEach accepts two arguments (not one).
These arguments are: index and value, the type of the index argument is number NOT string.
It is my fault for not spotting the problem, and for that I apologise.

Luckily the solution is pretty simple we just change this:

jsonOptions.forEach(function(item) {

To this:

// "i" stands for "index"
jsonOptions.forEach(function(i, item) {

I've corrected the problem and here is the edited JavaScript:

// Sorry for using "document.querySelector" I was far too lazy to use anything else :)
var dataList = document.querySelector("#auto_json_datalist");
var inputBox = document.querySelector(".enter_sym_i");
// Create a new XMLHttpRequest.
var request = new XMLHttpRequest();
// Handle state changes for the request.
request.onreadystatechange = function(response) {
  if (request.readyState === 4) {
    if (request.status === 200) {
      // Parse the JSON
      var jsonOptions = JSON.parse(request.responseText);
      // Loop over the JSON array.
      // The function inside "forEach" accepts two arguments, "index" and "value".
      // The problem was that the "index" argument is a "integer" NOT a string.
      jsonOptions.forEach(function(index, value) {
        // !! This is the if condition that checks the first character of the input value
        if(inputBox.getAttribute("value").charAt(0) == value.charAt(0)) {
          // Create a new <option> element.
          var option = document.createElement("option");
          // Set the value using the item in the JSON array.
          option.setAttribute("value", value);
          // Add the <option> element to the <datalist>.
          dataList.appendChild(option);
        }
      });
    } else {
      // An error occured :(
    }
  }
};
// Set up and make the request.
request.open("GET", "autocompleteSym.json", true);
request.send();

NOTE: please remember that it is good practice to use element.getAttribute("..."); and element.setAttribute("...", "..."); to set and get attributes and deal with the DOM "as is" (I.E: dealing with literal text only), instead of using properties.
If you would like more information on this you should check this question out.

Good luck and all the best.

Community
  • 1
  • 1