Reputation: 433
Im trying to make a search engine on key up to return results from DB but also if phrase has been typed to pull results from object not from DB
For example : when you type "BMW 300" will pull data from DB and will save phrase and results in object , and object will look like this
object {
b: (4) […]
0: Object { name: "BMW"}
1: Object { name: "BMW 300"}
2: Object { name: "BMW XS"}
3: Object { name: "BMW Z 500"}
bm: (4) […]
0: Object { name: "BMW"}
1: Object { name: "BMW 300"}
2: Object { name: "BMW XS"}
3: Object { name: "BMW Z 500"}
bmw: (4) […]
0: Object { name: "BMW"}
1: Object { name: "BMW 300"}
2: Object { name: "BMW XS"}
3: Object { name: "BMW Z 500"}
"bmw 3": (1) […]
0: Object { name: "BMW 300"}
"bmw 30": (1) […]
0: Object { name: "BMW 300"}
"bmw 300": (1) […]
0: Object { name: "BMW 300"}
}
if you delete 300 phrase is become "BMW" now should pull results from object because phrase "BMW" has been typed .
I code both logic and they work perfect , but the problem is how to swap when to read from object and when to read from DB ?
// create object
var hold_results = {};
$('input[name="search"]').on('keyup', function(){
var phrase = jQuery.trim($(this).val());
if (phrase.length > 0) {
$.ajax({
type: "POST",
url: 'index.php?route=product/newsearch',
data: 'phrase='+phrase,
success: function(data) {
if (data.length != 0) {
// push phrase and currect results in object
hold_results[phrase] = data;
$.each(data , function(key, value){
if (value != '') {
html = '<li><a href="'+value.href+'">'+value.name+'</a></li>';
$('#search-results').append(html);
}
});
}
}
});
}
// should pull results from object here if phrase exist
$.each(hold_results , function(key , value){
if (key == phrase) {
$.each(value, function(k , v){
html = '<li><a href="'+v.href+'">'+v.name+'</a></li>';
$('#search-results').append(html);
})
}
});
});
Upvotes: 4
Views: 620
Reputation: 6606
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:
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:
.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.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.
Upvotes: 1
Reputation: 301
You can simply check whether a phrase
already exists in holds_results
object and if it doesn't fetch it from db
// create object
var hold_results = {};
$('input[name="search"]').on('keyup', function(){
var phrase = jQuery.trim($(this).val());
if (phrase.length > 0) {
if (hold_results[phrase]) {
// should pull results from object here if phrase exist
$.each(hold_results , function(key , value){
if (key == phrase) {
$.each(value, function(k , v){
html = '<li><a href="'+v.href+'">'+v.name + '</a></li>';
$('#search-results').append(html);
})
}
});
}
else {
$.ajax({
type: "POST",
url: 'index.php?route=product/newsearch',
data: 'phrase=' + phrase,
success: function (data) {
if (data.length != 0) {
// push phrase and currect results in object
hold_results[phrase] = data;
$.each(data, function (key, value) {
if (value != '') {
html = '<li><a href="' + value.href + '">' + value.name + '</a></li>';
$('#search-results').append(html);
}
});
}
}
});
}
}
});
Upvotes: 0