gestalt
gestalt

Reputation: 375

How To Get jQuery-UI Autocomplete To Trigger On Key Press

I'm not quite sure if what I want is possible. But I currently have some code that populates an autocomplete list. The source is handled by an ajax call to a web api, that returns a set of items from the database (see code below).

$(".ItemSearch").on('keypress', function (event, ui) {
    var disabled = true;
    if (event.which === 13) {
        disabled = false;
    }
});

function BindItemNumberSearch(hostItemForm) {        
    if ($(".ItemSearch", hostItemForm).autocomplete({}).data("ui-autocomplete")) {
        $(".ItemSearch", hostItemForm).unbind("autocomplete");
        $(".ItemSearch", hostItemForm).autocomplete({
            close: function () {
                // some logic
            },
            response: function (event, ui) {
                // some logic if the item is empty
            },
            source: function (request, response) {
                // return if the search box is empty or is disabled
                if (request.term.trim().length <= 0 || disabled) {
                    return;
                }

                $.ajax({ 
                    // some ajax call
                });
            },
            delay: 500,
            focus: function (event, ui) {
                return false;
            },
            select: function (event, ui) {
                // return false if no item is selected
                if (ui.item.id != null) {
                    return false;
                }

                // some logic to select the item
            }
        }).data("ui-autocomplete")._renderItem = RenderSearchResultItem;
    }           
}

The issue we are having is that sometimes the request to search can be sent before the user has finished typing out the search string. This used to be OK as the search would return quickly, but now we have too much data and it is causing slowness (we think due to multiple searches being kicked off as the user slowly types what they are looking for).

So we would like to add a trigger on key press (such as the enter key) to kick off the search. I have found this answer, and it seems jQuery-ui does not support this. I've tried different attempts, the one included is the latest. However I can't seem to get it to work.

Upvotes: 2

Views: 1817

Answers (1)

95faf8e76605e973
95faf8e76605e973

Reputation: 14191

You can assign a flag for when your autocomplete should start searching.

// this will be the flag if autocomplete should begin searching
// should become true when [Enter] key is pressed & input field is not empty
window.BeginSearch = false;

After that, attach a DOM Event to your autocomplete element that would detect the Enter key

$(document).on("keydown", "#tags", function(e) {
    ...
})

Programatically instruct the autocomplete to start searching as needed when the Enter key is pressed

$("#tags").autocomplete("search");

Inside the source callback, this is when the flag variable will come in handy. Use this to detect if Enter key was pressed and therefore have set BeginSearch to true

$("#tags").autocomplete({
    source: function (request, response) {
        if (window.BeginSearch != true || request.term.trim().length <= 0) {
            response([]);
            window.BeginSearch = false; // reset the flag since searching is finished
            return;
        } else if (window.BeginSearch == true) {
            sample_async_function(request).then(function (return_data) {
                response(return_data);
                window.BeginSearch = false; // reset the flag since searching is finished
            });
        }
    },
    delay: 0 // no need for delay, as you can see
});

Sample Demo:

// this event will be responsible for tracking [Enter] key press
$(document).on("keydown", "#tags", function(e) {

  // additional checks so that autocomplete search won't occur if conditions are not met
  if (e.key == "Enter" && $("#tags").val().trim().length > 0 && $(".sample-loader:visible").length < 1) {
    window.BeginSearch = true;
    $("#tags").autocomplete("search");
  }
})

$(document).ready(function() {

  // this will be the flag if autocomplete should begin searching
  // should become true when [Enter] key is pressed & input field is not empty
  window.BeginSearch = false;

  $("#tags").autocomplete({
    source: function(request, response) {
      if (window.BeginSearch != true || request.term.trim().length <= 0) {
        response([]);
        window.BeginSearch = false; // reset the flag since searching is finished
        return;
      } else if (window.BeginSearch == true) {
        sample_async_function(request).then(function(return_data) {
          response(return_data);
          window.BeginSearch = false; // reset the flag since searching is finished
        });
      }
    },
    delay: 0 // no need for delay, as you can see
  });

});

// sample asynchronous function. mimics fetching data from server side (e.g., ajax) 
function sample_async_function(some_passed_string) {
  $(".sample-loader").show();
  return new Promise(resolve => setTimeout(() => {
    $(".sample-loader").hide();
    resolve(
      [
        "ActionScript",
        "AppleScript",
        "Asp",
        "BASIC",
        "C",
        "C++",
        "Clojure",
        "COBOL",
        "ColdFusion",
        "Erlang",
        "Fortran",
        "Groovy",
        "Haskell",
        "Java",
        "JavaScript",
        "Lisp",
        "Perl",
        "PHP",
        "Python",
        "Ruby",
        "Scala",
        "Scheme"
      ].filter((val, index) => {
        if (val.toLowerCase().includes(some_passed_string.term.toLowerCase())) {
          return val;
        }
      })
    );
  }, 500)); // arbitrary value. sample speed of the API XHR in unit milliseconds
}
.sample-loader {
  display: none;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1053;
  background: #000000dd;
  color: white;
  font-size: 20px;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>

<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>

<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

<div class="ui-widget">
  <label for="tags">AutoComplete: </label>
  <input id="tags">
</div>

<div class="sample-loader">Loading...</div>

From a UX perspective, you are going to want to figure out how to temporarily disable interactions with the element when the searching is in progress. In this example, I have used a simple "loading" screen.

Upvotes: 4

Related Questions