jQuery autocomplete timeout - javascript

For some reason the ajax requests I make on the website I'm working on abort half of the time. This is resolved when I set a timeout for the ajax request like shown below.
$.ajax({
url: "/question/why_wont_it_work",
timeout : 1000,
success: function(){ /*do stuff*/ }
});
Sadly the timeout fix doesn't seem to work with the jquery autocomplete. I'm using it like this:
$( "#questionTags" ).autocomplete({
source: "/question/tags",
timeout: 1000,
select: function(event, ui) { /*do stuff*/ },
});
I checked the jQueryUI documentation on the website and didn't see the timeout option there either. Now this is pretty annoying since half of the time my request will abort and I won't get the results
I want. Is there a way around this?
Thanks in advance.

You can supply an arbitrary function to the source parameter. So you could manually make an AJAX request and specify the timeout option:
var xhr = null; /* To prevent multiple calls from happening while one is in progress */
$("#questionTags").autocomplete({
source: function (request, response) {
if (!xhr) {
xhr = $.ajax({
url: "/question/tags",
timeout: 20000,
data: request,
dataType: "json",
success: function (data) {
xhr = null;
response(data);
},
error: function () {
response([]);
}
});
}
},
select: function(event, ui) { /*do stuff*/ },
});
But I'm with #El Ronnoco, you probably want to seriously speed up your request. 20 seconds is a long time to wait.

If source is a string, jQuery autocomplete does the code shown below to load the data, so it doesn't set a timeout.
You could set the timeout globally by using ajaxSetup like this:
$.ajaxSetup({
timeout: 20000,
});
But that would affect all your ajax requests.
Code from jquery.ui.autocomplete.js :: _initSource
self.xhr = $.ajax({
url: url,
data: request,
dataType: "json",
context: {
autocompleteRequest: ++requestIndex
},
success: function( data, status ) {
if ( this.autocompleteRequest === requestIndex ) {
response( data );
}
},
error: function() {
if ( this.autocompleteRequest === requestIndex ) {
response( [] );
}
}
});

$target.autocomplete('/question/why_wont_it_work',{
delay: 2000
});

Related

Depending on type of AJAX request show LoadingGif

I have 1 POST ajax and 1 GET ajax, and I have this:
$(document).ready(function () {
$(document).ajaxStart(function () {
$("#div28").show();
});
$(document).ajaxStop(function () {
$("#div28").hide();
});
});
It is for showing the LoadingGif, at this point it is showing for both Ajax requests, so what should I do to make the LoadingGif show only when the POST type ajax is working?
EDIT:
Here are my ajax functions:
$(document).ready(function () {
$.ajax({
contentType: "application/json; charset=utf-8",
type: 'GET',
url: 'api/Appointments/',
dataType: 'json',
success: function (result) {
if ((result.AppTime = "9:00") && (result.AppWithYritys = "Laakkonen")) {
document.getElementById("A9").style.background = "red";
}
else {
alert("error1");
}
},
error: function (error) {
alert("error");
},
});
});
and the POST ajax:
var request = $.ajax({
type: "POST",
data: JSON.stringify(app),
url: "/api/Appointments",
contentType: "application/json",
dataType: "html"
});
request.done(function (data) {
if (data != -1) {
alert("You Have successfully made an appointment");
location.assign("http://tid.fi");
}
else {
alert("There has been an error!");
}
});
request.fail(function (gr) {
location.assign("http://google.com");
});
};
POST ajax is in a custom function which is trigger on a button-click. Just an info.
using ajaxSend and ajaxComplete you can see what the "type" of request is
However, you'll need to keep a count of active requests too - possibly not required for your simple page - but it's good to have
$(document).ready(function () {
var started = 0;
$(document).ajaxSend(function (event, jqXHR, settings) {
if (settings.type == 'POST') {
if(!(started++)) { // only need to show on the first simultaneous POST
$("#div28").show();
}
}
});
$(document).ajaxComplete(function (event, jqXHR, settings) {
if (settings.type == 'POST') {
if(!(--started)) { // only hide once all simultaneous POST have completed
$("#div28").hide();
}
}
});
});
Solution without counters
$(document).ready(function () {
$(document).ajaxSend(function (event, jqXHR, settings) {
if (settings.type == 'POST') {
$("#div28").show();
}
});
$(document).ajaxStop(function () {
$("#div28").hide();
});
});
This will show on POST, and hide once all ajax has stopped - a little less obvious, but it's probably just as valid a solution
I think the easiest option is to create a tiny functions that you can use:
function showLoading(isLoading){
if(isLoading){
$("#div28").show();
}
else{
$("#div28").hide();
}
};
Then use as documented here Ajax events
just use the function either using the global events for your specific post or call the function directly on the beforeSend and complete event hooks.

AJAX request not executing inside chrome alarm

I am fairly new to AJAX and recently I've implemented chrome alarm in my background script. Here is my background.js :
chrome.alarms.onAlarm.addListener(function(alarm) {
alert("Begin");
$.ajax({
type: "GET",
url: "myURLhere",
datatype : 'jsonp',
crossDomain: true,
success: function(res)
{
alert('Success1');
},
error: function() {
alert("Error occurs!");
}
});
alert("We're done");})
So the problem is that, without the alarm my ajax request was executing successfully but now its never going into the success part. I always get 3 alerts (Begin,Error occurs! and We're done) and I have been wondering why since past few days.
Here is my popup.js file where the alarms are being set.
var alarmClock = {
onHandler : function(e) {
chrome.alarms.create("myAlarm", {delayInMinutes: 0, periodInMinutes: 2} );
window.close();
},
offHandler : function(e) {
chrome.alarms.clear("myAlarm");
window.close();
},
setup: function() {
var a = document.getElementById('alarmOn');
a.addEventListener('click', alarmClock.onHandler );
var a = document.getElementById('alarmOff');
a.addEventListener('click', alarmClock.offHandler );
}}; document.addEventListener('DOMContentLoaded', function () { alarmClock.setup(); });
Thanks in advance :)

how to delay select-2, so that it waits for some time after user types in data

I know that the above can be achieved by using quietMillis in the AJAX call, but I am using query to cache the data. And it is here I am not able to delay the AJAX call. Below is the code
$('#AssetType').select2({
cacheDataSource: [],
placeholder: ' ',
quietMillis: 3000,
query: function q(query) {
self = this;
var key = query.term;
var cacheData = self.cacheDataSource[key];
if (cacheData) {
query.callback({
results: $.map(cacheData, function (item) {
return {
text: item.LongDescription,
id: item.AssetTypeID
}
})
});
return;
}
else {
$.ajax({
url: 'http://localhost:52377/api/reference/asset/types/' + key,
dataType: 'json',
type: 'GET',
quietMillis: 3000,
//data: function (query) {
// return { assetType: query.term, };
//},
success: function (data) {
self.cacheDataSource[key] = data;
query.callback({
results: $.map(data, function (item) {
return {
text: item.LongDescription,
id: item.AssetTypeID
}
})
});
},
cache: true
})
}
}
});
Is there any work around to delay the AJAX call so that the AJAX call is not fired for every keystroke?? The reason for using "query" is for caching, which is not achieved just by setting cache to true in the AJAX call.
According to the select2 documentation, you can do this easily.
A request is being triggered on every key stroke, can I delay this?
By default, Select2 will trigger a new AJAX request whenever the user changes their search term. You can set a time limit for debouncing requests using the ajax.delay option.
This will tell Select2 to wait 250 milliseconds before sending the request out to your API.
$('select').select2({
ajax: {
url: '/example/api',
delay: 250
}
});
I found a way to delay the triggering. I've used an implementation of debounce function in underscore.js . The code would now look like this
query: debounce(function q(query) {..
.....
}, 350),
Hope it helps someone.
Select2 (4.0.3) has an undocumented option: minimumInputLength
This option will prompt the user to fill in the minimum number of characters and then fire the selection

How to set Custom Header for all xmlHttpRequest

I have to add customheaders to all ajax requests . I'm able to do this using the following code .Except in one case.
$.ajaxPrefilter(function (options) {
if (!options.beforeSend) {
options.beforeSend = function (xhr) {
xhr.setRequestHeader('Token', '1234');
}
}
});
Suppose if we are putting beforesend in $.ajax request , the above prefilter is not firing (example below). Can you please tell me how can I acheive it by keeping both?. Is there any way can we add header to xmlHttpRequest so that we can use for all ajax requests that are going from application?
$("#AdvancedserchClick").on("click", function () {
$.ajax({
async: false,
cache: false,
type: "POST",
url: getUrlWithTabId("#Url.Action("AdvancedSearch", "AdvancedSearch")"),
beforeSend: function () {
Load.show();
},
success: function (result) {
$("#advancedsearch").modal('show');
$("#advancedsearch").html(result);
},
complete: function () {
Load.hide();
}
});
});
You can achieve this by using the below code
$.ajax({
url: 'foo/bar',
headers: { 'x-my-custom-header': 'some value' }
});
Or you can use pre-filter would be an easy way of accomplishing this but this way all requests will get the custom header, unless the specific request overrides the beforeSend option.
$.ajaxPrefilter(function( options ) {
if ( !options.beforeSend) {
options.beforeSend = function (xhr) {
xhr.setRequestHeader('CUSTOM-HEADER-KEY', 'CUSTOM-HEADER-VALUE');
}
}
});
Hope this helps.
$.ajaxPrefilter(function( options, originalOptions, xhr ) {
xhr.setRequestHeader('Token', '1234');
});
Docs say :
jQuery.ajaxPrefilter( [dataTypes ], handler )
Description: Handle custom Ajax options or modify existing options before
each request is sent and before they are processed by $.ajax()

Synchronous Ajax requests "lock" browser

I have a couple of jQuery Ajax requests, which have to be synchronous, but they keep locking/freezing the browser, until the response is received. My main problem is, that until the response is received I have to display a spinning icon, but due to the freezing the spinner is not displayed and even if it miraculously is it doesn't animate.
This is the event displaying the spinner and sending the request:
$(document).on('click', '#open-button', function () {
var input = "some text";
var wrapper = $('#wrapperWindow');
wrapper.children().animate({
opacity: 0
}, 500);
wrapper.children().remove();
wrapper.append('<div id="loading-spinner" style="display:none;"></div>');
var spinner = $('#loading-spinner');
spinner.css({
backgroundImage: 'url("img/loading.gif")',
opacity: 0
});
spinner.show();
spinner.animate({
opacity: 1
}, 500);
var dataForTab = requestData(input); //<-- the request
if (dataForTab.length > 0) {
//do stuff
}
});
The request:
function requestData(input) {
var result = null;
$.ajax({
async: false,
type: "POST",
url: "/some/url?input=" + input,
dataType: "json",
retryLimit: 3,
success: function (json) {
result = json;
},
error: function (xhr, err) {
console.log(xhr);
console.log(err);
}
});
return result;
}
Until the request returns the received JSON data, everything stops moving. How can I fix this please?
That's the essence of synchronous requests, they are locking. You may want to try to move the requests to a web worker. Here's an example (not using XHR, but it can give you an implementation idea)
A web worker is implemented in a separate file, the scripting can look like:
onmessage = function (e) {
var result = null;
$.ajax({
async: false,
type: "POST",
url: "/some/url?input=" + input,
dataType: "json",
retryLimit: 3,
success: function (json) {
result = json;
postMessage({result: result});
},
error: function (xhr, err) {
postMessage({error: err});
}
});
}
Depending on your use case you can use something like
task.js Simplified interface for getting CPU intensive code to run on all cores (node.js, and web)
A example would be
// turn blocking pure function into a worker task
const syncWorkerRequest = task.wrap(function (url) {
// sync request logic
});
// run task on a autoscaling worker pool
syncWorkerRequest('./bla').then(result => {
// do something with result
});
You should not be doing this though, unless you need to do some heavy data processing, please use async requests.

Categories