Reputation: 375
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
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
});
// 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