Facebook Style AJAX Search - javascript

I've created a Facebook style ajax search for my site where as you type it will bring up the results in a nice list below your search.
$("#s").keyup(function() {
var searchbox = $(this).val();
var dataString = 's='+ searchbox;
if(searchbox!='') {
$.ajax({
type: "POST",
url: "/livesearch.php",
data: dataString,
cache: false,
success: function(html){
$("#display").html(html).show();
}
});
} else {return false; }
});
$("body").click(function() {
$("#display").hide();
});
The problem with this is it's a little ineffective as the user will type a word for example "football". This will carry out 8 requests to the server. What would be a more effective way to do this? ideally i think it should store the request for 1 second before doing a search rather than instant keyup. but not 100% sure how to do that...

the method you are referring to is called "Debouncing"
I usually have a "Debounce" function at the bottom of all my scripts
var debounce=function(func, threshold, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
};
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
};
And then whenever I do anything that will benefit from a debounce I can use it generically
So your code would be re-written as
$("#s").keyup(debounce(function() {
var searchbox = $(this).val();
var dataString = 's='+ searchbox;
if(searchbox!='') {
$.ajax({
type: "POST",
url: "/livesearch.php",
data: dataString,
cache: false,
success: function(html){
$("#display").html(html).show();
}
});
} else {return false; }
}
,350 /*determines the delay in ms*/
,false /*should it execute on first keyup event,
or delay the first event until
the value in ms specified above*/
));

Another option would be to start searching after 2/3 characters. Waiting for 1 second before making every request doesn't look good to me. Also try to send very less data back to server which might also make the request and response faster.

You could have a JSON object sitting somewhere and searching that instead of searching the database multiple times. It won't bring too much overhang, as long as it's not a list of 1,000 friends or something.

Related

how to wait check ajax request has completed before other element?

I have following code, where for each Image it makes ajax call. but my problem is like when it make ajax call for first image,at that time without waiting for respose it invokes for the second.so it hasn't get effect of first call,means I missed the first call effect. similary without waiting for second it is inovking for third,...
so how to wait in above each function until response come?
jQuery('.xxx img[src*="mainimage"]').each(function () {
vobj = $(this);
var inmainurl = 'https://xxx.kki/api/oembed.json?url=' + $(this).attr('src');
$.ajax({
url: inmainurl,
dataType: 'json',
success: function (result) {
$(vobj).attr('src',result.thumbnail_url);
}
});
});
You should use a recursive function for these purposes. Basic example (jsFiddle):
var myMethod = function(index){
var total_images = $('img').length;
if( index == total_images ) return; // job finished
var current_image = index || 0;
$.ajax({
/*...*/
success: function(/*...*/){
/*...*/
myMethod(current_image + 1);
}
});
};
myMethod();
You could make it synchronous by adding async: false to the ajax parameters. Then you can call them one after the other.
Or, if you want a bit more flexibility, put the ajax call into a function, passing in the image to load. Then in the "success" method of the ajax call, call the function again, passing in the next image name. You'll need some sort of list of image names so that the recursive calls can work out the next image to pass in, in each case.
After every ajax success callback, set some data-* attribute to loaded element and call the same function again.
Try this:
function loadOnlyOneImage() {
var vobj = $('.xxx img[src*="mainimage"][data-loaded!="true"]:first');
if (vobj.length) {
var inmainurl = 'https://xxx.kki/api/oembed.json?url=' + vobj.attr('src');
$.ajax({
url: inmainurl,
dataType: 'json',
success: function(result) {
vobj.attr('src', result.thumbnail_url);
vobj.attr('data-loaded', true);
loadOnlyOneImage();
}
});
}
}
loadOnlyOneImage();

setInterval and Ajax

I have this problem when I use setInterval and ajax for retrieving data from the database and if the data that I retrieve from the database is equal to saveHere then it will loop again until it does not match the variable saveHere, it freeze the browser until the data that I retrieve is not equal to saveHere.
Here is an example:
var saveHere = 'RED';
var interval = setInterval(function() {
var sample = $.ajax({
type: 'GET',
url: 'database.php',
data : data
}).responseText;
if (sample != 'RED') {
clearInterval(interval);
saveHere = sample;
}
else {
console.log('load again');
}
},1000);
I really need advice. Thank you in advance. Sorry for the grammar.
$.ajax is asynchronous and requires you to use a callback to get the response text.
Take a look at the documentation at http://api.jquery.com/jQuery.ajax/
What you want to do is to add a success parameter. Something like this:
var saveHere = 'RED';
doAjax();
function doAjax() {
$.ajax({
type: 'GET',
url: 'database.php',
data: data,
success: function (sample) {
if (sample != 'RED') {
saveHere = sample;
} else {
console.log('load again');
doAjax();
}
}
});
}
Notice how I've removed setInterval and instead wrapped the Ajax code in a function. The success callback will be called when the Ajax query has successfully finished, and give you the response. Once we have evaluated the response, we can run the doAjax function again to run the query again.
Without knowing the exact scenario, or what you're looking to achieve, I'd say the way you're going about your AJAX calls is very dangerous as it has the potential to constantly make a request every second, regardless of whether the server has had a chance to respond yet.
I'd be tempted to only make one request at a time, something like:
var saveHere = 'RED';
makeAjaxCall();
function makeAjaxCall() {
var url = 'database.php';
var data = {};
$.get(url, data, function(response_text){
if (response_text != 'RED')
{
saveHere = response_text;
// do whatever else you need...
}
else
{
// make another call...
console.log('calling again...');
makeAjaxCall();
}
}, "text");
}
You are clearing interval that means no interval will occur after that.
Instead what you can do is wrap interval inner code inside if condition as below.
var interval = setInterval(function()
{
if(sample != 'RED') {
var sample = $.ajax({
type: 'GET',
url: 'database.php',
data : data
}).responseText;
saveHere = sample;
}
else
{
console.log('load again');
}
},1000);
In your code you test for not equal to 'RED'.
if(sample != 'RED'){ . . .
That part of the loops stops the interval
If it doesn't equal red
}else{
It simple logs 'load again' without clearing the interval
What exactly are you trying to achieve ?

Looping through array with callback

I am trying to run through a array send to a php file and on a callback send the next value after the php has completed its download. Here what i have so far.
my array come through as follows.
["http://example.com/test1.zip", "http://example.com/test2.zip", "http://example.com/test3.zip", "http://example.com/test4.zip", "http://example.com/test5.zip"]
above is the output from console.log(values); below. it grabs some urls from checkbox values.
$('.geturls').live('click',function(){
var values = new Array();
$.each($("input[name='downloadQue[]']:checked"), function() {
values.push($(this).val());
ajaxRequest($(this).val(),function(response){
console.log(response);
});
});
console.log(values);
return false;
});
this then calls a ajax function which i am trying to do a callback on.
function ajaxRequest(urlSend,callback){
var send = {
url: urlSend
}
$.ajax({
type: "POST",
url: "<?php echo base_url(); ?>index.php/upload",
data: send,
//dataType: "json",
//timeout: 8000,
beforeSend: function() {
},
success: function(response) {
callback('added');
},
error: function (response) {
callback('false');
}
});
}
this will then send to a php file.
function upload(){
$output = shell_exec("wget {$_POST['url']} 2>&1");
return true;
}
What i am trying to do is after the callback from one url which it has download fully then grab the next value from the array and download that url and so on until all the urls in the array are downloaded fully.
at the moment it just downloads the first value and then crashes because it doesn't restart the loop after a return value of true is returned.
Hope this makes sense to someone just looking for some help on the best way to loop through an array of values with a callback after complete.
May be this structure can help you. In this variant you go next URL only after successful completion of the previous Ajax call.
var arr = ['url0','url1','url2','url3'];
var index = 0;
function Run(){
DoAjax(arr[index]);
}
function Next( ){
if(arr.count = index-1)
{
index =0;
return;
}else{
DoAjax(arr[index ]);
}
}
function DoAjax(url){
$.ajax({
type: "POST",
url: url,
data: send,
beforeSend: function() {
},
success: function(response) {
index ++;
Next();
// Addition logic if needed
},
error: function (response) {
}
});
}
Run()
Now that I have a bit more time, I thought it would be good to show an alternative which takes advantage of the fact that jquery ajax is now implemented as a deferred. Meaning you can use pipe chaining to do all the work for you. I've also eliminated the callbacks by taking advantage of the deferred behavior.
This should give you the idea.
// Use jquery deferred pipe chaining to force
// async functions to run sequentially
var dfd = $.Deferred(),
dfdNext = dfd,
x,
values = [],
// The important thing to understand here is that
// you are returning the value of $.ajax to the caller.
// The caller will then get the promise from the deferred.
ajaxRequest = function (urlSend) {
var send = {
url: urlSend
}
return $.ajax({
type: "POST",
url: "<?php echo base_url(); ?>index.php/upload",
data: send,
});
};
// Starts things running. You should be able to put this anywhere
// in the script, including at the end and the code will work the same.
dfd.resolve();
// Deferred pipe chaining. This is the main part of the logic.
// What you want to note here is that a new ajax call will
// not start until the previous
// ajax call is completely finished.
// Also note that we've moved the code that would
// normally be in the callback.
// Finally notice how we are chaining the pipes by
// replacing dfdNext with the return value from the
// current pipe.
for (x = 1; x <= 4; x++) {
values.push(x);
dfdNext = dfdNext.pipe(function () {
var value = values.shift();
return requestAjax(value).
done(function(response) {
// Code here that you would have
// put in your callback.
console.log(response);
}).
fail(function(response) {
console.log(response);
};
});
}
Working example you can play with on jsFiddle.

Wait for AJAX before continuing through separate function

Alright... at 2am, this is where I draw the line. Help... before my laptop ends up going out the window. :)
I've tried using setTimer, callbacks, and everything else I can think of (along with a few other Stackoverflow hints of course). I've stripped out everything so I'm leaving just the base code.
What I'm looking to do is call parseRow() and before it saves the record at the end, I need to grab the associated Category (via AJAX); however, it blows right past it so category is always "undefined".
function parseRow(row){
var rowArray = row.trim().split(",");
var date = rowArray[0];
var checknum = rowArray[1];
var payee = rowArray[2];
var memo = rowArray[3];
var amount = rowArray[4];
//ERROR: blows right past this one and sets the category variable BEFORE ajax returns
var category = autoSelectCategory(payee);
saveRecord(date, checkNum, payee, memo, category, payment, deposit);
}
function autoSelectCategory(payee) {
var data;
$.ajax({
async: false,
url: "autoselectcategory",
dataType: "json",
data: {
string: payee
},
success: function (returnedData) {
data = returnedData;
}
});
return data;
}
AJAX stands for asynchronous. That means that in your original code, saveRecord will be executed before the client will receive the response from the server (and, depending on the $.ajax implementation, it might be before the client will send the request to the server).
Additionally, you seem to misunderstand how functions work in JS. var category = autoSelectCategory(payee); will set the category to the return value of autoSelectCategory; but the autoSelectCategory function in your code returns nothing.
From the other side, the data return value of your anonymous function could only be used by $.ajax function (and $.ajax likely ignores the success parameter return value).
Here is the code that should work:
function parseRow(row){
var rowArray = row.trim().split(",");
var date = rowArray[0];
var checknum = rowArray[1];
var payee = rowArray[2];
var memo = rowArray[3];
var amount = rowArray[4];
autoSelectCategory(payee, function (category) {
saveRecord(date, checkNum, payee, memo, category, payment, deposit);
});
}
function autoSelectCategory(payee, callback) {
$.ajax({
async: false,
url: "autoselectcategory",
dataType: "json",
data: {
string: payee
},
success: callback
});
}
Do not use async: false option. It's a pure evil (blocks all scripts in browser and even other tabs!) and it's deprecated since jQuery 1.8. You should use callbacks as it was always meant to be.
function parseRow(row) {
/* the other code */
autoSelectCategory(payee, function() {
saveRecord(date, checkNum, payee, memo, category, payment, deposit);
});
}
function autoSelectCategory(payee, callback) { // <---- note the additional arg
$.ajax({
url: "autoselectcategory",
dataType: "json",
data: {
string: payee
},
success: function(res) {
/* the other code */
callback();
}
});
}

Javascript ajax queue system needed. Cross domain jsonp. How would i do this.

I have this javascript code which i want to change into a queue system. Currently i am having to code it like this. It becomes messy when there are a long chain of requests.
Note: My functions requests return json objects.
Setting async to false is not used for cross domain jsonp calls so wont work.
Calls have to be made in this order.
Jquery queues wont work.
var customers;
var orders;
var products;
function GetCustomers(){
$.ajax({
url: somecrossdomainurl?calback=GetCustomerCallback,
dataType: 'jsonp',
async: false
});
}
function GetCustomerCallback(data){
customers=data;
GetCustomersOrder();
}
function GetCustomersOrder(){
$.ajax({
url: somecrossdomainurl?calback=GetCustomersOrderCallback,
dataType: 'jsonp',
async: false
});
}
function GetCustomersOrderCallback(data){
orders = data;
GetOrderProducts();
}
function GetOrderProducts(){
$.ajax({
url: somecrossdomainurl?calback=GetOrderProductsCallback,
dataType: 'jsonp',
async: false
});
}
function GetOrderProductsCallback(data){
products = data;
DisplayCustomersAndOrder();
}
function DisplayCustomersAndOrder(){
//loop round customer,order,products and display info
}
//I want to do something like this:
function DisplayData(){
var queue;
queue.GetCustomer();
queue.GetCustomersOrders();
queue.GetOrderProducts();
queue.DisplayCustomersAndOrder();
queue.Start()
}
Any suggestions
This is an implementation of an async queue using promises.
https://gist.github.com/thejuan/5697765
It's in TypeScript, but very little too do to change into pure JS.
It continues on error, if you dont want it to there are simpler solutions than this (just chain each of your calls by using then)
Note: Requires Jquery 1.8 or higher when they made .then behave "correctly"
export class AsyncExecutionQueue{
private tail: JQueryPromise = $.Deferred().resolve();
public enqueue(cmd:()=>any): JQueryPromise {
console.log("Queuing Command");
var next = $.Deferred();
var client = $.Deferred();
this.tail.always(() => {
try {
var result = cmd();
if (result.done && result.fail) {
result
.done(client.resolve, next.resolve)
.fail(client.reject, next.resolve);
}
else {
client.resolve(result);
next.resolve();
}
}
catch (e) {
client.reject(e);
next.resolve();
}
});
this.tail = next;
return client;
}
}

Categories

Resources