I have been searching and this problem seems simple but cannot find answer. I have multiple request calling different url. But for each url, I only want the result once and it must be the last one in the same url being called. My issue now is "how to get the last one only?" I looked at this and it seems to be 3 years old:
http://plugins.jquery.com/project/ajaxqueue
Any other way to do this nicely and cleanly? If there is something like this, it would be perfect:
queue: "getuserprofile",
cancelExisting: true
(where the existing ajax in getuserprofile queue will be canceled)
Thanks
This explains how to use jQuery to do an ajax call and how to abort it. All you need to do is create an array that stores each request. You could then cancel the previous request while adding the new one.
ajaxRequests = new Array();
queueRequest = function() {
if(ajaxRequests[ajaxRequests.length - 1]) {
ajaxRequests[ajaxRequests.length - 1].abort();
}
ajaxRequests[ajaxRequests.length] = //Insert New jQuery AJAX call here.
}
Since we only want the result of the last request, this is very simple and works.
var ajax = null;
var getFoo = function() {
if(ajax) ajax.abort();
ajax= $.ajax({});
};
getFool();
getFool();
getFool();
getFool();
getFool();
getFool();
only the last request is executed.
Instead of using library, you can use Basic jquery Ajax method :
beforeSend:{}
For example:
xhr = jQuery.ajax({
url: /*Your URL*/
type: "POST",
data: {
//data
},
/* if there is a previous ajax request, then we abort it and then set xhr to null */
beforeSend : function() {
if(xhr != null) {
xhr.abort();
}
},
success:function(){}
});
Yes it's posibble...
In general, I do not recommend stopping requests on the server side, there may be some problems that are hard to detect later.
The idea is to just check the status of a sent request and if necessary, just not send another one.
Here is an example
let activeRequest = false; //global var
let request = null;
$(document).ready(function(){
$('#user').keyup(function(){
let query = $(this).val();
if (query != '') {
const xhr = new XMLHttpRequest();
if (activeRequest === false){
activeRequest = true;
let request = $.ajax({
url: 'https://baconipsum.com/api/?type=all-meat',
method: "POST",
beforeSend: function(){
//Some code here
},
data: {
"type": $(":radio:checked").val(),
"tags": query,
},
success: function (data) {
//Code if succes
console.log('Request with val: ' + query);
},
complete: function() {
activeRequest = false;
}
});
if(!request){
console.log('Req does exist');
}
request.done(function( ) {
activeRequest = false;
console.log('Done, Request Finish');
request = false;
});
}else{
//If ajax still request abort it
console.log('Exiting Request - LastOne Still In que')
//request.abort();
activeRequest = true;
}
} //End iF query != ''
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" name="user" id="user" style="width: 200px;" placeholder="Enter User Name" />
It takes some work to customize it for you but I think it will help guide everyone for you.
//Edit
I forgot, u can customize this code, for example add
let value = $('#output').val();
value.slice(0,-1);
If the request is still pending... Or just another idea, just block the possibility of entering more characters, there are plenty of solutions
Related
I have a data coming to NodeJS and then it needs to be served to Ajax query. but because the NodeJS is transfering it as chunked data, none of the general Javascript/JQuery ajax methods are able to capture the packet.
How can i get the values
nodeJS:
http.createServer(options, (req, res) => {
msg = c++_to_javascript();
res.writeHead(200);
res.end(msg);
}).listen(89);
Javascript/JQuery:
received the data as transfer encoded: chunked as a result no methods are able to decode the received packets in JS.
How could i solve it from NodeJS or in JS?
TRY 1: FAILED
$.stream(javascript_to_c++,{
open:function(){
console.log("opened");
},
message:function(event){
console.log(event.data);
buf1 = buf1 + event.data;
},
error:function(){
console.log("error");
},
close:function(){
console.log("closed");
}
});
TRY2 : FAILED
var test = $.ajax({
type: "GET",
url: javascript_to_c++,
async: false,
success:function(m) {
buf1 = buf1 + m;
}
}).responseText;
console.log(test);
TRY 3: FAILED
// Define a method to parse the partial response chunk by chunk
var last_index = 0;
function parse(xhr) {
var curr_index = xhr.responseText.length;
if (last_index == curr_index) return; // No new data
var s = xhr.responseText.substring(last_index, curr_index);
last_index = curr_index;
console.log(s);
}
function test() {
var xhr = new XMLHttpRequest();
var url = javascript_to_c++;
xhr.open("GET", url, true);
xhr.send();
// Check for new content every 5 seconds
var interval = setInterval(parse, 5000);
// Abort after 25 seconds
setTimeout(function(){
clearInterval(interval);
parse(xhr);
xhr.abort();
}, 25000);
}
test();
You just have to properly wait for the response to come back. I'm not too familiar with the other ajax methods you're using but let's look at this for example:
var test = $.ajax({
type: "GET",
url: javascript_to_c++,
async: false,
success:function(m) {
buf1 = buf1 + m;
}
}).responseText;
console.log(test);
Are you expecting test to be the response? $.ajax returns a Promise representing the asynchronous request. It's not until the success callback is called or the promise is resolved when you'll get the response text. Try this instead:
var test = $.ajax({
type: "GET",
url: javascript_to_c++, // I'm assuming this is a valid URL?
success:function(content) {
console.log(content); // This is your actual full response.
}
});
As far as having the node process specify the content type, try the content-type header:
res.set('content-type', 'text/plain');
res.end(msg);
Update:
As already pointed out, it's highly doubtful that the Transfer-Encoding thing is actually a problem. It you do want to disable it, do:
res.set('transfer-encoding', '');
...but really, it shouldn't be necessary.
Another Update:
Not using Express? You'll just need to slightly modify this:
res.writeHead(200, {
'content-type': 'text/plain',
'transfer-encoding': '' // not recommended...
});
res.end(msg);
I've been working on getting a function written to:
1) Process an input array using $.ajax calls to fill an output array (below this is inputList)
2) Below is what I have, but I'm having issues with it:
requestData(), when I call it, runs straight through to processing the outputList array without having fully populated/filled it - it puts one value into it then starts to process that, but the function still apparently runs on seperately to the subsequent processing asynchronously. I need it to be fully synchronous so that it does not return until the inputList array has been fully processed.
I'm not seeing the browser repainting the div that has its html updated on every call of the runajax() function - I'm attempting to do this with a setTimeout.
3) I've set the ajax request to be synchronous (async : false) - but this doesn't seem to help
I've tried to use jQuery's $.when to provide an ability to ensure that everything gets called in sequence - but clearly I'm not doing this correctly.
Would appreciate any help - I've asked previous related questions around this and had some useful help - but I've still not resolved this!
Thanks
//declare holding function requestData - expects a non-empty input data array named inputList
function requestData() {
//declare inner function runajax
function runajax() {
if(inputList.length > 0) {
//get first item from inputlist and shorten inputList
var data = $.trim(inputList.shift());
function getData() {
//send the data to server
return $.ajax({
url: 'sada_ajax_fetch_data.php',
cache: false,
async: false,
method: "post",
timeout: 2000,
data: {
requesttype: "getmydata",
email: encodeURIComponent(data)
}
});
}
function handleReturnedData (response) {
response = $.trim(decodeURIComponent(response));
//update the div inner html
if(response == "Failed") {
$('#fetchupdatestatus').html('There was an error retrieving the data you requested!');
} else {
$('#fetchupdatestatus').html('The item returned was '+response);
}
//add the response from ajax to the end of the outputList array
outputList.push(response);
//set up the next ajax call
var doNextBitOfWork = function () {
runajax();
};
//call setTimeout so that browser shows refreshed div html
setTimeout(doNextBitOfWork, 0);
//return
return $.when();
}
//do the next ajax request and response processing
return getData().done(handleReturnedData);
} else {
//did the last one so return
return $.when();
}
}
//kick off the ajax calls
runajax();
}
var inputList = new Array();
var outputList = new Array();
.....load +/- 100 values to be processed using ajax into array inputList
requestData();
.....process stuff in array outputList
.....etc
There was my answer with "you're doing it wrong" earlier, but then I just decided to show, how you can do it (almost) right: https://jsfiddle.net/h4ffz1by/
var request_maker = {
working: false,
queue: [],
output: [],
requestData: function(inputList) {
if (request_maker.working == true) {
return false;
}
request_maker.output = [];
request_maker.working = true;
while (inputList.length > 0) {
var data = $.trim(inputList.shift());
request_maker.queue.push(data);
}
console.log(request_maker.queue);
request_maker.doTheJob();
return true;
},
doTheJob: function() {
current_data_to_send = request_maker.queue.shift();
console.log(current_data_to_send);
if (typeof current_data_to_send != 'undefined' && request_maker.queue.length >= 0) {
$.ajax({
url: '/echo/json/',
cache: false,
method: "post",
timeout: 2000,
data: {
requesttype: "getmydata",
email: encodeURIComponent(current_data_to_send)
},
success: function(data, status, xhrobject) {
console.log(xhrobject);
request_maker.handleReturnedData(data);
},
});
} else {
request_maker.working = false;
console.log('all data has been sent');
}
},
handleReturnedData: function(response) {
console.log(response);
response = $.trim(decodeURIComponent(response));
//response= 'Failed';//uncomment to emulate this kind of response
if (response == "Failed") {
$('#fetchupdatestatus').append('There was an error retrieving the data you requested!<br/>');
} else {
$('#fetchupdatestatus').append('The item returned was ' + response + '<br/>');
request_maker.output.push(response);
}
request_maker.doTheJob();
if (request_maker.working == false) {
console.log('all requests have been completed');
console.log(request_maker.output);
}
}
}
inputList = [1, 2, 3, 4, 5, 6];
if (request_maker.requestData(inputList)) {
console.log('started working');
}
if (!request_maker.requestData(inputList)) {
console.log('work in progress, try again later');
}
Note that I've changed request path to jsfiddle's ajax simulation link and replaced html() with append() calls to print text in div. The calls are made and get handled in the same order as it is in inputList, still they don't lock user's browser. request_maker.output's elements order is also the same as in inputList.
Have in mind, that you will need to add error handling too (probably just a function that pushes 'error' string into output instead of result), otherwise any ajax error (403/404/502, etc.) will get it "stuck" in working state. Or you can use complete instead of success and check request status right there.
UPD: Answer to the question: you cannot get both. You either use callbacks and let browser repaint inbetween asynchroneous requests or you make requests synchroneous and block browser untill your code finished working.
UPD2: There actually is some information on forcing redraw, however I don't know if it will work for you: Force DOM redraw/refresh on Chrome/Mac
I am attempting to follow the advice within this question to fit the following scenario:
On keyup, send an AJAX request to the server with the term in the input field. But if they continue to type, abort any existing AJAX requests so only one request is sent.
Here is my code as it stands:
jQuery(document).ready(function($) {
var $input = $('#s'),
inputVal = '',
inputCount = '';
function process_asr_request() {
$.ajax({
url: MyAjax.ajaxurl,
data: {
'action':'pondera_asr_request',
'inputVal' : inputVal
},
success:function(data) {
$('#search-results').append( data )
},
error: function(errorThrown){
console.log( errorThrown);
}
});
}
$input.on("keyup", function() {
// record the value of the input
inputVal = $input.val(),
// check the lenght on the value
inputCount = inputVal.length,
// define array for ajax requests
requests = [];
// Only process once there are 3 characters
if (inputCount > 2) {
// push ajax requests into the array
requests.push(
process_asr_request(i)
);
// loop through the array of requests
for(
var i = 0;
i < requests.length;
i++
)
// kill any queued requests
requests[i].abort();
};
});
});
I have two questions:
Is this approach valid for what I am looking to achieve
I get an "Uncaught TypeError: Cannot call method 'abort' of undefined" error with the above code. Where am I going wrong.
I'm fairly new to AJAX so please pardon my naivety.
Close, just need to return the xhr so you can abort it:
function process_asr_request(inputVal) {
return $.ajax({
url: MyAjax.ajaxurl,
data: {
'action':'pondera_asr_request',
'inputVal' : inputVal
},
success:function(data) {
$('#search-results').append( data )
},
error: function(errorThrown){
console.log( errorThrown);
}
});
}
Also this loop would be better written as below, so old xhrs are removed from requests:
var xhr;
while (xhr = requests.pop()) {
// kill any queued requests
xhr.abort();
}
requests.push(process_asr_request(inputVal));
Another note, requests should be outside the event loop if you want this to work and you have several globals in this function.
var requests = [];
$input.on("keyup", function() {
var inputVal = $input.val(),
// check the lenght on the value
inputCount = inputVal.length;
//...
});
var currXHR;
function process_asr_request() {
if(currXHR && currXHR.abort) currXHR.abort();
currXHR = $.ajax({
url: MyAjax.ajaxurl,
data: {
'action':'pondera_asr_request',
'inputVal' : inputVal
},
success:function(data) {
$('#search-results').append( data )
},
error: function(errorThrown){
console.log( errorThrown);
}
});
}
I use Prototype.js to validate a form. For one of the fields, I have the prototype script ajax a request to a file. The file is a simple PHP file and will return '1' if the value is OK and '0' if the value is not OK. I have the script as below, which should work perfectly. The prototype validation is supposed to show a validation error message when a field does not pass validation, and not display / remove the message once the field passes validation. But in this case, even when the ajax file returns '1', the validation will display the error message anyway. Anyone able to help would be greatly appreciated!
['validate-number3', numessage3, function(v) {
new Ajax.Request('test.php?nr='+v, {
method:'get',
onSuccess: function(transport) {
var response = transport.responseText;
if(response == '1'){return true;}else{return false};
}
});
}],
the return value from Ajax.Request is the Ajax.Request object and returns as soon as the request is setup - the onsuccess callback is called after the request has been completed - so checking the results of Ajax.Request is not useful for what you want to accomplish.
The reason that this doesn't work as you expect, this is an asynchronous call which means it will start the call and then return control to the script while it is processing and then run the callbacks when it is completed.
Try it this way
new Ajax.Request('test.php?nr='+v, {
method:'get',
onSuccess: handleResponse
});
function handleResponse( transport ){
var response = transport.responseText;
if(response == '1'){
//everything is OK
}else{
//value is not OK
};
}
I was able to solve my question!
Thanks to this teriffic page: http://inchoo.net/ecommerce/magento/magento-frontend/magento-form-field-ajax-validation/ it was no problem. This is what I ended up with:
var ok = false;
new Ajax.Request('test.php?nr='+v, {
method:'get',
asynchronous: false,
onSuccess: function(transport) {
var response = transport.responseText;
if(response == '1'){ok = true;}else{ok = false;};
},
onComplete: function() {
if ($('advice-validate-number-pay_bank_no')) {
$('advice-validate-number-pay_bank_no').remove();
}
}
});
return ok;
I am trying to do 2 ajax function calls when a user clicks a button.
I have
$('.test').on('click', function(){
code.getCode();
code.getText();
})
code.prototype.getCode=function(){
var call=//call ajax
call.callback= function(data){
//parse return data
}
}
code.prototype.getText=function(){
var call=//call ajax
call.callback= function(data){
//parse return data
}
}
I can only do 1 ajax call and only 1 ajax call will return data.
I am not sure how to solve this. Any ideas? Thanks a lot!
I am not sure if I understood correctly, but I think you are looking for a single callback from both the ajax calls..
You should use $.when.done. See below,
$.when($.ajax("/page1.php"), $.ajax("/page2.php")).done(function(a1, a2){
/* a1 and a2 are arguments resolved for the
page1 and page2 ajax requests, respectively */
var jqXHR = a1[2]; /* arguments are [ "success", statusText, jqXHR ] */
if ( /Whip It/.test(jqXHR.responseText) ) {
alert("First page has 'Whip It' somewhere.");
}
});
Not sure if you looking for sequencing it or trying to have 1 callback.
You could also have the first ajax call, call the second on success:
$('.test').on('click', function(){
var datastr = "your data";
$.ajax({
type: "POST",
url: "url",
data: datastr,
success: function(successMsg) {
//ajax done
if (/* not yet complete */) {
setTimeout(secondAjaxCall(),500);
} else {
secondAjaxCall();
}
}
});
});
You could just save each return in the code object (since you are in a different context you have to work around "this"). Then you can use a third function that checks if the data objects are loaded... and start parsing once both are there.
$('.test').on('click', function(){
code.getCode();
code.getText();
})
code.prototype.getCode=function(){
var call=//call ajax
var that = this;
call.callback= function(data){
//parse return data
that.codeData = data;
parseData();
}
}
code.prototype.getText=function(){
var call=//call ajax
var that = this;
call.callback= function(data){
//parse return data
that.textData = data;
parseData();
}
}
function parseData() {
if(!code.textData || !code.codeData) return;
... work with both
}