There is a simple approach to achieve that - But first you need to be aware that your implementation will fire too many times and may not work as expected.
I would consider adding several things:
- Aborting previously fired async ajax requests before firing the new search - In your code it will just keep firing and receive many results that may not be relevant any more.
- Add a Caching mechanism - you want to control how much records it will store and you want a good way to match required search terms (Exact match OR subsets OR both).
Here is Demo in JSfiddle - I will walk you through
First we create a variable that will hold an active ajax request otherwise will be null
:
//this is the variable that will store the ajax call
var request = null;
Now we can create an Object that will be our Cache system with all the required methods:
var cache = {
storageFIFO: [], // The array that will hold our results
maxResults: 20, // max enteries in the storedResultFifo array - will shift once when exceeded
pushResults: function(phrase, data) {
cache.storageFIFO.push({
term: phrase,
data: data
});
if (cache.storageFIFO.length > cache.maxResults) {
cache.storageFIFO.shift();
}
},
getCachedResults: function(phrase) {
//First try exact match against cached search terms:
for (var i = 0; i < cache.storageFIFO.length; i++)
if (cache.storageFIFO[i].term === phrase)
return cache.storageFIFO[i].data;
//try phrase as a substring of the terms stored in the cache
for (var i = 0; i < cache.storageFIFO.length; i++)
if (cache.storageFIFO[i].term.includes(phrase))
return cache.storageFIFO[i].data;
return false;
}
};
A few notes about the Cache:
- FIFO (first in first out) : When storage limit is reached the oldest record is removed.
.shift();
Will pop the first element (index 0 which is the oldest) to achieve the FIFO like data structure.
getCachedResults
: this method will try to match the phrase twice - Once for an exact match (for better results) otherwise will try to match the phrase as a subset of the cached terms.
string1.includes(string2)
this is the way that I match subsets.
Now that the cache mechanism is set - I put the logic inside the keyup
event:
//Bind the event to search:
$('input[name="search"]').on('keyup', function() {
var phrase = jQuery.trim($(this).val());
if (phrase.length <= 1) return; // From length of two
//This is just for testing and generating random data:
var randomData = [];
for (var i = 0; i < Math.floor(Math.random() * (20 - 5 + 1)) + 5; i++)
randomData.push({
phrase: phrase,
href: "#",
name: Math.random().toString(36).substring(7)
});
//This will trigger an abort of previous unfinished ajax request
//When aborted the ajax `complete` will set it back to null
if (request != null) request.abort();
//try to load from Cache first:
var fromCache = cache.getCachedResults(phrase);
if (fromCache !== false) {
drawResults(fromCache, "Cached Results");
return;
}
//If we got here that means that the cache does not has matching phrases:
//Send a request to db:
request = $.ajax({
url: '/echo/json/', // A jsfiddle async request endpoint
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: { //the correct data structure for jsfiddle async requests
json: JSON.stringify(randomData),
delay: 0.15
},
success: function(data) {
if (data.length != 0) {
//Cache it:
cache.pushResults(phrase, data);
//Draw it:
drawResults(data, "DataBase");
}
},
complete: function() {
request = null;
}
});
});
Here you can see some additional stuff that is for the jsfiddle created (to get results from a dummy async request server).
A few notes about the Logic and Ajax request:
if (phrase.length <= 1) return;
: will prevent queries that are not 2 chars and longer.
if (request != null) request.abort();
: will abort previously running requests. As you can see in the Ajax complete
callback it will set it back to null
when finished (success, abort, error etc...)
cache.getCachedResults(phrase);
: First try from cache - Will return false
if no match.
- After no hits againts the cache - then an ajax is fired (note that the url, and data is modified to the required values to work with jsfiddle).
Final Notes
Drawing the results is up to you - I just included a small quick function to visualize the results and to see where they came from.