In a jquery Ajax call I am currently handling statusCode of 200 and 304. But I also have "Error" defined" To catch any Errors that could come back.
If there is a validation message related we return the status code of 400 - Bad Request.
This then falls into the "Error" function before falling into the statusCode "400" function I had defined. Which means two actions happen.
Ideally I would like to not define "Error" and "Success" and only define "statusCode" But what I need is to have a "Else" so that I don't need to declare every statusCode that exists only the 2-3 I want to handle differently.
$.ajax({
type: 'POST',
contentType: "application/json",
url: "../API/Employees.svc/" + EmployeeId + "/Company/" + CompanyId,
data: jsonString,
statusCode: {
200: function () { //Employee_Company saved now updated
hideLoading();
ShowAlertMessage(SaveSuccessful, 2000);
$('#ManageEmployee').dialog('close');
},
304: function () { //Nothing to save to Employee_Company
hideLoading();
$('#ManageEmployee').dialog('close');
if (NothingToChange_Employee) {
ShowAlertMessage(NothingToUpdate, 2000);
} else {
ShowAlertMessage(SaveSuccessful, 2000);
}
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
AjaxError(XMLHttpRequest, textStatus, errorThrown);
}
});
Since the "complete" event is always fired you could simply get the status code from there and ignore the success and error functions
complete: function(e, xhr, settings){
if(e.status === 200){
}else if(e.status === 304){
}else{
}
}
This is what i'd use:
error: function (xhr, textStatus, errorThrown) {
switch (xhr.status) {
case 401:
// handle unauthorized
break;
default:
AjaxError(xhr, textStatus, errorThrown);
break;
}
}
jQuery AJAX response complete, success, error have been deprecated. More up-to-date version with .done, .fail, .always promise instead.
On success .always has signature of .done, on failure it's signature changes to that of .fail. Using the textStatus you can grab the correct variable and return the body contents.
var jqxhr = $.ajax( {
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
dataType: 'json',
} )
.done(function( data, textStatus, jqXHR ) {
alert( "success" );
})
.fail(function( jqXHR, textStatus, errorThrown ) {
alert( "error" );
})
.always(function( data_jqXHR, textStatus, jqXHR_errorThrown ) {
if (textStatus === 'success') {
var jqXHR = jqXHR_errorThrown;
} else {
var jqXHR = data_jqXHR;
}
var data = jqXHR.responseJSON;
switch (jqXHR.status) {
case 200:
case 201:
case 401:
default:
console.log(data);
break;
}
});
jqxhr.always(function() {
alert( "second complete" );
});
To keep the approach similar to your initial logic, I would continue passing a statusCode object. However, you still know that "else" will fall in the realm of 4xx or 5xx type error codes.
So I would update your original code to:
var statusCodeResponses = {
200: function () { //Employee_Company saved now updated
hideLoading();
ShowAlertMessage(SaveSuccessful, 2000);
$('#ManageEmployee').dialog('close');
},
304: function () { //Nothing to save to Employee_Company
hideLoading();
$('#ManageEmployee').dialog('close');
if (NothingToChange_Employee) {
ShowAlertMessage(NothingToUpdate, 2000);
} else {
ShowAlertMessage(SaveSuccessful, 2000);
}
}
};
var genericElseFunction = function(response){
// do whatever other action you wanted to take
};
for(var badResponseCode=400; badResponseCode<=599; badResponseCode++){
statusCodeResponses[badResponseCode] = genericElseFunction;
}
$.ajax({
type: 'POST',
contentType: "application/json",
url: "../API/Employees.svc/" + EmployeeId + "/Company/" + CompanyId,
data: jsonString,
statusCode: statusCodeResponses,
error: function (XMLHttpRequest, textStatus, errorThrown) {
AjaxError(XMLHttpRequest, textStatus, errorThrown);
}
});
Related
I have an Ajax Call to an API which will return correctly (200) when the URL and the parameters are fine. Now I am trying to force an error with a bad request. Console will inform me about error code 400 but never seems to get into the error method. Instead it gets stuck in some jquery line and never returns.
fetch: function(successCallback, errorCallback) {
var apiUrl = this.applyFilter(filters);
var self = this;
this.log('fetch', apiUrl, currentSearchMode);
$.ajax({
url: apiUrl,
type: 'GET',
cache: (debug) ? true: false,
processData: true,
crossDomain: true,
scriptCharset: 'UTF-8',
jsonp: 'callback',
dataType: 'jsonp',
success: function(data, statusText, jqXHR) {
console.log(jqXHR);
// if(jqXHR.status == 400){
// console.log('there is an error');
// }
self.log('fetch::success', data);
if (typeof data.error !== 'undefined') {
showNoResultError = true;
var appData = lastValidResult[currentSearchMode];
} else {
showNoResultError = false;
var appData = self.normalize[currentSearchMode](self, data);
lastValidResult[currentSearchMode] = appData;
}
if (typeof successCallback === 'function')
successCallback(appData);
},
error: function(jqXHR, textStatus, errorThrown) {
//do sth here
// if(jqXHR.status&&jqXHR.status==400){
// alert(jqXHR.responseText);
// }else{
// alert("Something went wrong");
// }
// console.log('works now');
// self.log('fetch::error', textStatus, errorThrown);
// if (typeof errorCallback === 'function')
// errorCallback.apply(this, arguments);
},
complete: function(jqXHR, textStatus) {
console.log(jqXHR);
console.log('complete');
}
});
},
So the image shows where it gets stuck. I can only catch complete and success functions but when there a 400 response there is nothing happening. Tried anything, also done(), fail() since I assumed there might be a problem with deprecated behavior. But same problem there. Can anybody help, please?
Try:
fetch: function(successCallback, errorCallback) {
var apiUrl = this.applyFilter(filters);
var self = this;
this.log('fetch', apiUrl, currentSearchMode);
$.ajax({
url: apiUrl,
type: 'GET',
cache: (debug) ? true: false,
processData: true,
crossDomain: true,
scriptCharset: 'UTF-8',
jsonp: 'callback',
dataType: 'jsonp',
success: function(data, statusText, jqXHR) {
console.log(jqXHR);
// if(jqXHR.status == 400){
// console.log('there is an error');
// }
self.log('fetch::success', data);
if (typeof data.error !== 'undefined') {
showNoResultError = true;
var appData = lastValidResult[currentSearchMode];
} else {
showNoResultError = false;
var appData = self.normalize[currentSearchMode](self, data);
lastValidResult[currentSearchMode] = appData;
}
if (typeof successCallback === 'function')
successCallback(appData);
},
error: function(data){
console.log(data);
console.log(data.responseText);
},
complete: function(jqXHR, textStatus) {
console.log(jqXHR);
console.log('complete');
}
});
},
then, show me what's in your console
Error callback will not be fired for crossdomain requests or for jsonp requests.
search for the below in the reference link.
Note: This handler is not called for cross-domain script and cross-domain JSONP requests.
Reference: http://api.jquery.com/jquery.ajax/
You can look at this answer for how to handle errors for jsonp requests
JSONP request error handling
I am trying to catch specific response errors using jQuery's $.ajax.
When there is an 500 or 404 error code, instead of running the status code functions, it runs the error function and I get an alert box instead of what is supposed to happen
Here is what my code looks like
// get page data
getPageData: function(url, callback) {
url = ajaxLoader.getURL(url);
$.ajax({
url: url,
type: 'get',
data: {_ajax_loader: 1},
error: function(xhr, status) {
alert('There was a problem loading that page. You may need to refresh.');
},
statusCode: {
404: function(response) {
ajaxLoader.fetchPage('/missing');
},
500: function(response) {
ajaxLoader.fetchPage('/error');
}
}
}).done(callback);
},
This is by design. error is executed when an error is returned by the server. Further, the functions defined in statusCode are also called as well. The same applies to complete and success handlers.
You could modify your error handler not to run when the error code is already defined in statusCode.
$.ajax({
url: '/echo',
type: 'get',
success: function() {
console.log('ajax.success');
},
error: function(xhr, status) {
// check if xhr.status is defined in $.ajax.statusCode
// if true, return false to stop this function
if (typeof this.statusCode[xhr.status] != 'undefined') {
return false;
}
// else continue
console.log('ajax.error');
},
statusCode: {
404: function(response) {
console.log('ajax.statusCode: 404');
},
500: function(response) {
console.log('ajax.statusCode: 500');
}
}
});
Demo
The issue is that you are using the error callback in addition to the statusCode object. The error callback is triggered when any type of error occurs, including HTTP errors like 404 or 500.
To fix this, you need to remove the error callback and only use the statusCode object.
Here is the corrected code:
// get page data
getPageData: function(url, callback) {
url = ajaxLoader.getURL(url);
$.ajax({
url: url,
type: 'get',
data: {_ajax_loader: 1},
statusCode: {
404: function(response) {
ajaxLoader.fetchPage('/missing');
},
500: function(response) {
ajaxLoader.fetchPage('/error');
}
}
}).done(callback);
},
This way, only the appropriate function will be called when a 404 or 500 status code is returned, and not the error callback.
$.ajax has success and error functions, so you can handle it with jqXHR defined for both.
On success:
success: function(data, status, jqXHR) {
switch(jqXHR.status){
case 200:
//status ok
break;
case 206:
//Partial Content
//awesome code for handle it
break;
}
}
On error:
error: function(jqXHR, status, errorThrown) {
switch(jqXHR.status){
case 400:
//Bad Request
//awesome code for handle it
break;
case 404:
//Not Found
//awesome code for handle it
break;
}
}
Here all status codes
It will execute both the error and appropriate StatusCode function.
The only issue with your code is that in your StatusCode functions, you have the argument of response (which I assume is the argument for the success function), when it should match the error function arguments, as follows:
// get page data
getPageData: function(url, callback) {
url = ajaxLoader.getURL(url);
$.ajax({
url: url,
type: 'get',
data: {_ajax_loader: 1},
error: function(xhr, status) {
alert('There was a problem loading that page. You may need to refresh.');
},
statusCode: {
404: function(xhr, status) {
ajaxLoader.fetchPage('/missing');
},
500: function(xhr, status) {
ajaxLoader.fetchPage('/error');
}
}
}).done(callback);
},
With this, if a 404 or 500 is received, both the error function and the 404/500 function will execute. If you instead desire to have only the 404/500 function execute, and the error function will only execute if the returned status is not 404 or 500, you can do this as follows:
// get page data
getPageData: function(url, callback) {
url = ajaxLoader.getURL(url);
$.ajax({
url: url,
type: 'get',
data: {_ajax_loader: 1},
error: function(jqXHR, status) {
switch (jqXHR.status) {
case 404:
ajaxLoader.fetchPage('/missing');
break;
case 500:
ajaxLoader.fetchPage('/error');
break;
default:
alert('There was a problem loading that page. You may need to refresh.');
}
}
}).done(callback);
},
I am trying to set a button text to 'Email sent' on success or 'Emailed failed' on failure. I am using ajax to call a method in MVC.
The call to to MVC works fine, but my code calls setButtonSuccess and setButtonFailed even before the json is ran?
Here is my code:
$('input[type=button]').click(function () {
bookingID = $(this).closest('tr').attr('id');
sendEmail(bookingID, this);
});
function sendEmail(id, thisContext) {
var data = JSON.stringify({ 'id': id });
/*******
This calls setButtonSuccess AND setButtonFailed which is wrong
I want to execute only setButtonSuccess OR setButtonFailed depending on whether successful or not
*******/
jsonPOST("~Booking/ResendEmail", data, setButtonSuccess(thisContext, "Email Sent"), setButtonFailed(thisContext, "Email Failed"),false);
};
function setButtonSuccess(thisContext, buttonValue) {
$(thisContext).val(buttonValue);
$(thisContext).addClass("btn btn-success");
};
function setButtonFailed(thisContext, buttonValue) {
$(thisContext).val(buttonValue);
$(thisContext).addClass("btn btn-warning");
};
function jsonPOST (pWebServiceFunction, pData, pOnCallbackSuccess, pOnCallbackFailed, async) {
$.ajax({
type: "POST",
url: url + pWebServiceFunction,
data: pData,
contentType: "application/raw; charset=utf-8", dataType: "json",
async:async,
processdata: true,
success: function (msg) {
if (msg.success === true) {
pOnCallbackSuccess(msg);
}
else {
pOnCallbackFailed(url + pWebServiceFunction);
}
},
error: function (xhr, ajaxOptions, thrownError) //When Service call fails
{
pOnCallbackFailed(url + pWebServiceFunction, pData, xhr.status, xhr.statusText, xhr.responseText);
}
});
};
Thanks
You're calling the functions immediately instead of passing a function that will call them later. It should be:
jsonPOST("~Booking/ResendEmail", data, function() {
setButtonSuccess(thisContext, "Email Sent");
}, function() {
setButtonFailed(thisContext, "Email Failed");
}, false);
I have a javascript function like this :
addGas = function(options){
var working = false;
$(document).ajaxSend(function(event, jqxhr, settings) {
if (settings.url == '/add_gas') {
working = true;
}
});
if(working) {
return;
}
$.ajax({
url: options.url,
data: options,
type: "POST",
success: function(data, textStatus, jqXHR){
$(".btn").addClass("added").text(" Added gas ").prepend("<i></i>");
},
error: function(jqXHR, textStatus, errorThrown){
}
});
}
So the way I test this is that I put 10 seconds sleep in my controller, and try to click the button again, and it makes a post request who is waiting, because my server can server one request at a time.
But I wanted not to send a post request if one is already running, alternatively alert a message if the request is already running.
How can I do that?
Create a singleton handling its own state, this way you dont pollute the rest of the code with unused variables
gasHandlerBuilder = function(){
var ajaxInProgress = false;
return {
add_gas: function(options){
if(ajaxInProgress){ return; };
ajaxInProgress = true;
$.ajax({
url: options.url,
data: options,
type: "POST",
success: function(data, textStatus, jqXHR){
ajaxInProgress = false;
$(".btn").addClass("added").text(" Added gas ").prepend("<i></i>");
},
error: function(jqXHR, textStatus, errorThrown){
ajaxInProgress = false;
}
});
}
}
}
var gasHandler = gasHandlerBuilder();
gasHandler.add_gas(options);
You should use some flag, something like this :
var recieved = false;
$.ajax({
url: "http://first.call/",
})
.done(function( data ) {
// Do something with that data and enable the flag
recieved = true;
});
addGas = function(options){
var working = false;
$(document).ajaxSend(function(event, jqxhr, settings) {
if (settings.url == '/add_gas') {
working = true;
}
});
if(!recieved) {
return;
}
$.ajax({
url: options.url,
data: options,
type: "POST",
success: function(data, textStatus, jqXHR){
$(".btn").addClass("added").text(" Added gas ").prepend("<i></i>");
},
error: function(jqXHR, textStatus, errorThrown){
}
});
}
I have a function with an AJAX call inside it, I need to be able to call the function and it return true if the AJAX request was successful and false if not.
I know the following doesn't work because the returns are out of scope to the exampleFunc()
function exampleFunc() {
$.ajax({
url: 'http://example.com/page',
success: function(data, textStatus, XMLHttpRequest){
return true;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
return false;
}
});
}
I Googled for a solution and believe I should be doing a callback but couldn't seems to achieve the desired outcome.
Edit: Te be more specific I require the function to return true or false because my use case currently has me doing :
if (exampleFunc()) {
// run this code
}
You can't return from something asynchronous. The callback function has to do what you want to do in a forwards direction.
Simply pass the function to your exampleFunc() and call it in your ajax success callback.
// you want this function to be run on ajax success.
function sayHello() {
alert('hello');
}
function exampleFunc(callback) {
$.ajax({
url: 'http://example.com/page',
success: function(data, textStatus, XMLHttpRequest){
if (callback && typeof callback == 'function') {
callback() // here, you call sayHello, which is passed as parameter
}
return true;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
return false;
}
});
}
exampleFun(sayHello); // start ajax
function exampleFunc() {
$.ajax({
url: 'http://example.com/page',
async: false,
success: function(data, textStatus, XMLHttpRequest){
return true;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
return false;
}
});
}
Notice async: false
$.ajax is an asynchronous call which will have a callback handler on success/error response. To work around, you need to pass a callback.
function exampleFunc(callback, errorCallback) {
$.ajax({
url: 'http://example.com/page',
success: callback,
error: errorCallback
});
}
USAGE
exampleFunc(function(data, textStatus, XMLHttpRequest) {
// do whatever you want, you have got a success response
//return true;
}, function (XMLHttpRequest, textStatus, errorThrown) {
// error occured, show some red error box
//return false;
});
This can only be done if you got a sync function like:
function exampleFunc() {
var success;
$.ajax({
async : false,
url: 'http://example.com/page',
success: function(data, textStatus, XMLHttpRequest){
success= true;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
success= false;
}
});
return success;
}
What you can do is pass a function to your function. Something like:
var hello = "Hello World";
exampleFunc(function(){
alert(hello); // Alerts Hello World on success
},
function(){
alert("FAILED"); // Alerts FAILED on error
});
And the function will look like:
function exampleFunc(success, error) {
$.ajax({
url: 'http://example.com/page',
success: success,
error: error
});
}
But you can't change the hello var inside the function and use it after the function call. Because the call's keep async.