Method POST, Status (canceled) error message - javascript

I have the following code which is giving me a Method POST, Status (canceled) error message:
$(document).ready(function() {
var xhr = false;
get_default();
$('#txt1').keyup( function() {
if(xhr && xhr.readyState != 4){
alert("abort");
xhr.abort();
}
if ($("#txt1").val().length >= 2) {
get_data( $("#txt1").val() );
} else {
get_default();
}
});
function get_data( phrase ) {
xhr = $.ajax({
type: 'POST',
url: 'http://intranet/webservices.asmx/GetData',
data: '{phrase: "' + phrase + '"}',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function( results ) {
$("#div1").empty();
if( results.d[0] ) {
$.each( results.d, function( index, result ) {
$("#div1").append( result.Col1 + ' ' + result.Col2 + '<br />' );
});
} else {
alert( "no data available message goes here" );
}
},
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert(err.Message) ;
}
});
}
function get_default() {
$('#div1').empty().append("default content goes here.");
}
});
The code actually works as long as each ajax request completes, but if I type fast into txt1, i.e. type the next character before the previous request finishes, I get the error message Method POST, Status (canceled).
Anyone know why this is happening and how to correct the error?

I suppose that the problem is very easy. If you call xhr.abort(); then the error callback of $.ajax will be called for the pending request. So you should just ignore such case inside of error callback. So the error handler can be modified to
error: function(jqXHR, textStatus, errorThrown) {
var err;
if (textStatus !== "abort" && errorThrown !== "abort") {
try {
err = $.parseJSON(jqXHR.responseText);
alert(err.Message);
} catch(e) {
alert("ERROR:\n" + jqXHR.responseText);
}
}
// aborted requests should be just ignored and no error message be displayed
}
P.S. Probably another my old answer on the close problem could also interesting for you.

That is because you are calling abort method which possibly triggers the error handler with appropriate error message.
You can possibly wait for previous ajax request to complete before making the next call.

In order to both fix your problem and save on the amount of Ajax calls I have written the following example. This example allows you to handle the following two situations:
Situation 1:
The user types slow enough (lets say about one key every 200+ miliseconds
Situation 2:
The user types fast (my average is about 20 to 50 miliseconds per key)
In the following example there is no need to abort or ignore Ajax calls, you are not spamming Ajax calls and you are using an Object to handle your job. (I even jsFiddled it for you)
var Handler = {
/**
* Time in ms from the last event
*/
lastEvent: 0,
/**
* The last keystroke must be at least this amount of ms ago
* to allow our ajax call to run
*/
cooldownPeriod: 200,
/**
* This is our timer
*/
timer: null,
/**
* This should run when the keyup event is triggered
*/
up: function( event )
{
var d = new Date(),
now = d.getTime();
if( ( now - Handler.lastEvent ) < Handler.cooldownPeriod ) {
// We do not want to run the Ajax call
// We (re)set our timer
Handler.setTimer();
} else {
// We do not care about our timer and just do the Ajax call
Handler.resetTimer();
Handler.ajaxCall();
}
Handler.lastEvent = now;
},
/**
* Function for setting our timer
*/
setTimer: function()
{
this.resetTimer();
this.timer = setTimeout( function(){ Handler.ajaxCall() }, this.cooldownPeriod );
},
/**
* Function for resetting our timer
*/
resetTimer: function()
{
clearTimeout( this.timer );
},
/**
* The ajax call
*/
ajaxCall: function()
{
// do ajax call
}
};
jQuery( function(){
var field = jQuery( '#field' );
field.on( 'keyup', Handler.up );
});
Hope this helps.

You are using the keyup event, which seems to be the problem.
If anything at all, you need to wait after typing one character before taking action.
A better solution might be to follow the same strategy as the JQuery AutoComplete COmponent.

Ajax is an async type, its not recommonded that u to send request on every keyup event, try the...
async: false
in post method... it'll pause the subsequent posts until the current request done its callback

Realistically you need a setTimeout method in order to prevent redundant ajax calls being fired.
clearTimeout(timer);
if($("#txt1").val().length >= 2){
timer = setTimeout(function(){
get_data($("#txt1").val());
}, 400);
}else{
get_default();
}
This should eradicate your problem.

Related

How to execute jQuery AJAX calls in order?

I have an input field. Whenever there's change in the text in the input field, I make an ajax call to process.php
I need to handle all the responses. But some responses come early, whereas some come late, depending on the input. So the order of responses is not same as order of making ajax calls.
So right now I'm doing it by setting async: false
But I don't want the client side to be stuck due to async: false
$("#text_input").on("input", function() {
var password = $("#text_input").val();
var length = password.length;
$.ajax({
url: "process.php",
type: "POST",
async: false,
data: {
password: $(this).val()
}
}).done(function (data) {
console.log(data);
console.log(password + " : " + length);
}).fail(function( jqXHR, textStatus, errorThrown ) {
alert( "Request failed: " + textStatus + " , " + errorThrown );
});
});
I tried looking in promises, but did not understand whether it can be applied here.
How can I execute responses in order?
The problem with async is exactly that, that is asynchronous, that means that the code runs without waiting to finish. Therefore all your requests go to the server and once they start returning your code catches them and executes them.
If you want to handle them in order, you will need to build a queue and the code to handle the queue.
You should then assign an ordered number to all your requests which should then come in the response (so you know the proper order of the response).
Then you can add the response to the queue, and call a method which processes the queue, but that method only processes the queue in order, meaning that it only processes responses starting from 0, 1, 2, 3 etc... so if in the queue there is a result 5 and not a result 0, the queue won't be processed, the queue will be processed only if result 0 is there and so on...
Here is an example code, I haven't tested it but should work or at least should give you an idea on how to start :)
var currentOrder = 0;
var queue = [];
function processQueue() {
// Sort the queue
queue.sort(function(a, b) {
var aOrder = a.order;
var bOrder = b.order;
if (aOrder < bOrder) {
return -1;
}
if (aOrder > bOrder) {
return 1;
}
// Order is equal (this shouldn't happen)
return 0;
});
if (queue[0].order === currentOrder) {
doSomething(data);
queue.splice(0, 1); // Remove the first item from the queue as it's already processed
currentOrder++;
processQueue(); // Process the queue again
}
}
// Do something with the data
function doSomething(data) {
console.log(data);
}
$('#text_input').on('input', function() {
$.ajax({
url: 'process.php?order=' + order, // We send the order to the backend so it can be returned in the response
type: 'POST',
data: {
password: $(this).val()
}
}).done(function(data) {
// Data should contain the order somewhere, let's say for example it's a json and it's inside data.order
queue.push(data);
processQueue();
});
});
Assuming that you are only interested in the results of the latest ajax call, you can assign the value returned from the $.ajax call - a jqXHR object - to a variable and then abort the request when a new one is fired.
Something like:
var request = null;
$("#password_input").on("input", function() {
var password = $("#password_input").val();
var length = password.length;
// you can also check the type of the variable, etc.
if (request) {
request.abort();
}
request = $.ajax({
url: "process.php",
type: "POST",
...
Why not use setTimeout function to whenever they press some letter on your input field. you can do it just like this:
setTimeout(function(){
$.ajax({
url: "process.php",
type: "POST",
data: {
password: $(this).val()
}
}).done(function (data) {
console.log(data);
console.log(password + " : " + length);
}).fail(function( jqXHR, textStatus, errorThrown ) {
alert( "Request failed: " + textStatus + " , " + errorThrown );
});
}, 1000);
This is to setTimeout once the press on your input field and wait 1sec then when finished type on the input field it will generate the ajax after 1sec.

Retry ajax request after timeout

I'm using a prefilter to redo the ajax request 2 times max, see code below.
However the problem is that the original fail() handler of the ajax request is also called. This needs to be disabled of course.
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
// retry not set or less than 2 : retry not requested
if (!originalOptions.retryMax || !originalOptions.retryMax >= 2) {
return;
}
// no timeout was setup
if (!originalOptions.timeout > 0) {
return;
}
if (originalOptions.retryCount) {
originalOptions.retryCount++;
} else {
originalOptions.retryCount = 1;
// save the original error callback for later
if (originalOptions.error) {
originalOptions._error = originalOptions.error;
}
};
// overwrite *current request* error callback
options.error = $.noop();
// setup our own deferred object to also support promises that are only invoked
// once all of the retry attempts have been exhausted
var dfd = $.Deferred();
jqXHR.done(dfd.resolve);
// if the request fails, do something else yet still resolve
jqXHR.fail(function() {
var args = Array.prototype.slice.call(arguments);
if (originalOptions.retryCount >= originalOptions.retryMax || jqXHR.statusText !== "timeout") {
// add our _error callback to our promise object
if (originalOptions._error) {
dfd.fail(originalOptions._error);
}
dfd.rejectWith(jqXHR, args);
} else {
$.ajax(originalOptions).then(dfd.resolve, dfd.reject);
}
});
});
My request is: And i get the console.log message "we are in fail" at the same time as the request is redone for the first time. Any idea how to fix this?
$.ajax({
url: url,
crossDomain: true,
dataType: "json",
type: type,
timeout: 20000,
async: (async === undefined ? true : async),
beforeSend: beforeSend,
retryMax: (type == "POST" ? 0 : 2),
data: data
}).done(function(response, status, xhr) {
}).fail(function(xhr, textStatus, error) {
console.log("WE ARE IN FAIL");
});
easier way (sorry I only have the time to write partial code) :(
Create a recursive function that handle the ajax request and takes parameters + a counter.
var MyFuncAjax = function(params, counter){
if(counter <= 0){ return true; }
$ajax({
...
timeout: params.timeout
...
})
...fail(function(xhr...){
MyFuncAjax(params, --counter)
})
}
Then call it
MyFuncAjax({timeout: 20000, ....}, 2)
And voila :)

Form Submission vs AJAX Polling Call

Following up on my question from the other day, I've run into another thing that now I've spent too many hours banging my head against.
Mostly, I'm having trouble getting the SUCCESS form to submit. I tried this as well:
jQuery form submit
Here's the code in a semi-functional fiddle:
http://jsfiddle.net/ZcgqV/
Essentially what happens is this:
I bind a method to the form's submission via onSubmit (rather than click)
On submit, it calls a remote server via jQuery .ajax() call
If the response is "PENDING", retry every 1s, nine times
On failure, don't submit the form
On success, submit the form
No matter what I try, I can't get the form to either submit when I want it to without going into a loop, or not submit immediately while it tries the remote server.
~Frustrated-trying-100-things-that-fail-ly yours...
Here's the code directly in case you dislike fiddles:
var retries = 0;
var success = false;
var token = "toki wartooth is not a bumblebee";
$(document).ready(function() {
// Attach the action to the form
$('#tehForm').attr('onSubmit', 'onsubmit_action(event)');
});
function async(fn) {
setTimeout(fn, 1000);
}
function pollServer() {
$.ajax({
type: "POST",
cache: "false",
url: "/remoteCall",
dataType: "json",
data: {
ref_token: token
}
}).done(function(data, code, jqXHR) {
switch (data.status) {
case "SUCCESS":
alert("Success");
success = true;
// --> HERE IS WHERE I WANT THE FORM TO SUBMIT <--
break;
case "PENDING":
if (retries < 9) {
retries += 1;
async(function() {
pollServer();
});
} else {
alert("Failed after 9 tries");
}
break;
case "ERROR":
alert("Error");
break;
default:
alert("Some kind of horrible error occurred");
break;
}
}).fail(function(jqXHR, textStatus) {
var statusCode = jqXHR.status;
alert("Request failed: " + statusCode + " " + textStatus);
});
}
function onsubmit_action(event) {
pollServer();
if (success === false) {
// RETURN FALSE DIDN'T WORK, SO I FOUND THIS
event.preventDefault();
}
}​
EDIT:
Again, the real problem here is that I stop submission of the form. On SUCCESS, I want the form to submit. Currently if I use .submit() in SUCCESS, the AJAX is called again, starting the process over. What I want is the ACTION of the FORM to fire on SUCCESS only.
Trying to use as much of the original code as possible; here is a solution:
Post form with post back
http://jsfiddle.net/tpm7v/4/
Post form via Ajax
http://jsfiddle.net/tpm7v/5/
var retries = 0,
token = "toki wartooth is not a bumblebee",
sendRequest,
handelResponse,
postFormToServer,
$theForm = $('#tehForm');
$(document).ready(function() {
// Attach the action to the form
$theForm.bind('submit', onsubmit_action);
});
sendRequest = function() {
$.ajax({
type: "POST",
cache: "false",
url: "/remoteCall",
dataType: "json",
data: {
ref_token: token
},
success: handelResponse
});
};
postFormToServer = function() {
$.ajax({
type: "POST",
cache: "false",
url: "/remoteCallToTakFormData",
dataType: "json",
data: $form.serialize(),
success: function() {
alert('success!');
}
});
};
handelResponse = function(data, code, jqXHR) {
switch (data.status) {
case "SUCCESS":
postFormToServer();
break;
case "PENDING":
if (retries < 9) {
retries += 1;
setTimeout(sendRequest , 1000);
} else {
alert("Failed after 9 tries");
}
break;
case "ERROR":
alert("Error");
break;
default:
alert("Some kind of horrible error occurred");
break;
}
};
function onsubmit_action(evt) {
evt.preventDefault();
sendRequest();
}
​
​
Keep in mind I am going off the code your provided. You should be able to port this to work with your actual implementation. You may also want to try something like https://github.com/webadvanced/takeCommand to help clean up all the Ajax calls.
Please see my comment above for more information, but I think the problem you're seeing here is this:
Every time pollServer() fires, it's not only doing another ajax call, but it's prepping to do 9 possible ajax calls every second based on the retries loop. Since you're then setting another pollServer() call with the async() method, you're basically compounding your ajax calls out of control. You want to get the ajax call out of your retry loop, then you should at least be only getting 1 request a second, not 1, then 2, then 3, etc. I may have read the code wrong, but this is my best guess on what you're seeing.
UPDATE: I'm not sure my explanation was clear, so I thought I'd add some additional info. Basically, every time pollServer() is called and gets a PENDING response, it calls async, which registers a setTimeout(). setTimeout() keeps running every second, doing pollServer(), which then calls asynch, which registers another setTimeout() which also runs every second. Now you have two functions, which each then call setTimeout(), assuming they're still getting PENDING as a response from the server. So after 2 rounds of failed calls, you have 4 setTimeout() calls each firing an ajax call (and a new setTimeout) every second.
First off it should be: $('#tehForm').submit(onsubmit_action); or $('#tehForm').on("submit",onsubmit_action); or something like that. Never use the string form to pass a function. It uses the evil eval statement.
Next, after POST the data is already submitted. That is the whole reason for post. Why do you need all sorts of error handling in the done section. Fail should handle error handling.
If you are asking about how to try again after a timeout, try this:
Is it possible to check timeout on jQuery.post()?
I believe timeout will fall into fail.
So try this:
var retries = 0,
max_tries = 9,
success = false,
token = "toki wartooth is not a bumblebee";
$(document).ready(function() {
// Attach the action to the form
$('#tehForm').on("submit",submit_the_form);
});
function submit_the_form(e){
var dfd = $.ajax({
url : "sendTokenPolling",
data : {"token":token},
timeout : 5000 //you may want 1000, but I really think that is too short
});
dfd.done(function(){
//success, form posted
});
dfd.fail(function(){
//did not work/timedout
if (retries < max_tries){
retries += 1;
submit_the_form(e);
}
});
}

consecutive ajax calls freeze chrome and IE

i got a strange one. I have to make several consecutive ajax calls, and when a call is complete i update a progress bar. This works perfectly on FF but on the rest of the browsers what happens is that the screen freezes until all the calls are complete.
I am not executing the calls in a loop, but by using some sort of recursion cause there's a lot of checking that needs to be done and a loop is not convenient.
When i tried the same thing using a loop the outcome was more or less the same. Chrome or IE did not update the screen until all the ajax requests where done.
What i noticed is that it works ok on FF and opera, but chrome (safari too i suppose) and IE9 are behaving strange. Also on Chrome, during these requests, the response body of the previous request is empty and will remain like that until all requests are done.
Any ideas?
Code is extensive, but here goes. There is a wrapper to ajax, $(db).bind is a callback for success. db.records is the Json result. Model is an object holding several controller functions
$(db).bind('tokenComplete',function(){
var x = db.records;
if (!x.success) { model.callRollBack(); return false; }
var next = parseInt(x.get.num)+ 1;
if (typeof x.post.tokens[next] != 'undefined') {
model.executeToken(next,x.post);
}
else {
model.progressCurrent.find('div.report').html('all done!!');
}
});
model = {
drawProgressBarsTotal : function(el,i,v) {
var p = Math.floor(100 * i / versions.total);
el.find('span').html(p);
el.find('div.report').html('updating to : ' + v.version);
el.find('.changeLog').html(v.changeLog);
el.find('.changeLog').parents('div').show();
el.find('img').css({'background-position': 100 - p + '% 100%'});
},
executeToken : function(i,x) {
if (this.fail == true) { return; }
this.drawProgressBarsCurrent(this.progressCurrent,i+1,x);
db.trigger = 'tokenComplete';
db.data = x;
db.url = dbDefaults.url + '?num='+i+'&action='+x.tokens[i];//bring the first
$(db).loadStore(db);
}
}
loadStore :
$.dataStore = function( ds ) {
$.fn.loadStore = function(ds){
$.ajax({
type: ds.method,
url: ds.url,
data: ds.data,
dataType: ds.dataType,
cache:false,
async:true,
timeout:ds.timeout?ds.timeout:10000,
queue: "autocomplete",
contentType:'application/x-www-form-urlencoded;charset=utf-8',
accepts: {
xml: "application/xml, text/xml",
json: "application/json, text/json",
_default: "*/*"
},
beforeSend:function(){
loadStatus = true;
},
success: function(data) {
loadStatus = false;
if(data)
{ds.records=data;}
$(ds).trigger(ds.trigger);
},
error: function()
{
loadStatus = false;
$(ds).trigger('loadError');
}
});//END AJAX
};//END LOADSTORE
try {
return ds;
} finally {
ds = null;
}
}
}
Haven't followed your entire code, but it sounds like your problem may be related to continuous code execution. Typically the UI will not update during continuous code execution. To fix this, any call to a setTimeout() or any ajax calls should allow the browser time to update the UI. Basically, you must stop the code briefly, then start it again.
function updateUI () {
// change ui state
document.setTimeout( updateUI, 1 );
}
If I am off base here, let me know.

jQuery $.post() in recursive way (loop)

I learn jQuery and don't understand this situation:
When running this code in debug mode all work well. But when running this code normal, calback function don't starts. Why?
In non debug mode I have -> "Start" -> "End 10"
Browser: Google Chrome.
var nrPost = 10;
$("#buttnX").click(function() {
alert("Start");
GoPosts();
End();
});
function End() {
alert('End ' + nrPost);
};
function GoPosts() {
$.ajaxSetup({async:false});
var url = "http://......";
var data = { ... };
$.post(url, data, Callback, 'json');
};
function Callback(response) {
if (response.error) {
return;
}
nrPost--;
if (nrPost > 0) [
GoPosts();
} else {
return;
}
};
You had an extra }; in your code. I changed it around a bit to use jQuery and put it up on jsfiddle.
http://jsfiddle.net/rH8RV/19/
It should alert: "Start" and then "End 10", that's correct based on how you wrote your code. Were you expecting anything else?
I don't know what you're planning to do with your recursive implementation, but if that's all, you could actually do this:
function startLoop(nrPost) {
// No need to put this in a loop
$.ajaxSetup({ async: false });
for (var i = 0; i < nrPost; i++) {
alert('Start ' + i);
var url = 'http://......';
var data = {};
$.post(url, data, function (response) {
if (response.error)
return;
alert('End ' + i);
}, 'json');
}
}
$('#buttnX').click(function () { startLoop(10) });
Hope that helps!
I imagine you are expecting the display to be:
"Start"
"End 0"
This is unlikely to work with your solution.
Your Ajax call $.post(url, data, Callback, 'json'); is asynchronous. This means that once the $.post method returns, the request is sent to the URL you have provided. However, Callback is not called until JQuery receives the answers. What happens immediately is that GoPosts terminates and the program continues. It comes back to line 5 of your code, inside the anonymous function in your click handler. At that point, End() is called and alerts "End 10".
You probably want to put your call to End in Callback instead:
function Callback(response)
{
if (response.error)
{
return;
}
nrPost--;
if(nrPost>0)
GoPosts();
else
{
End(); // You only want to end once you have made you nrPost calls to GoPost
return;
}
};

Categories