AJAX promise call handling - javascript

I have an Ember promise call as below;
var promise = new Ember.RSVP.Promise(function(resolve, reject) {
return $.ajax({
//want this common
url: requestUrl,
type: type, // HTTP method
dataType: dataType, // type of data expected from the API response
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(postData)
})
.done(function(data, status, xhrObject) {
//But want this to be different
// resolve call
})
.fail(function(xhrObject, status, error){
// reject call
});
})
My question is can I use common code for $.ajax(), but have different implementation for done() callback
I can check that by passing some parameter from the calling place.
so basically, I want
if (someparam == 'handleDone1')
call resolve(data)
else
call resolve({data})

You are currently passing a function to done by hard coding a function expression into it.
Replace that with a variable. Pass a value to that variable as a function argument.
Alternatively, don't use done here at all. Just return the return value of $.ajax() and call done() on that in the calling function.

return a promise instead of ajax call. And wrap the ajax call into promise.
checkout the below code. It may helps.
function someFunction(resolve1, reject1) {
return new Ember.RSVP.Promise(function(resolve, reject) {
$.ajax({
//want this common
url: requestUrl,
type: type, // HTTP method
dataType: dataType, // type of data expected from the API response
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(postData)
})
.done(function(data, status, xhrObject) {
//But want this to be different
// resolve call
var dicision = resolve1();
if(dicision){
resolve(data);
} else {
resolve({data});
}
})
.fail(function(xhrObject, status, error){
// reject call
});
}

Related

jQuery $.ajaxError preventing ajax promise from being rejected

I have a WebApp with a lot of ajax calls, so I did the following to clean up things:
I defined an ajax call with default values:
$.ajaxCall = function (Params){
return $.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: Params.data,
url: Params.url,
});
};
I defined a global ajax errors handler:
$(document).ajaxError(function( event, xhr, settings, error ) {
if(xhr.hasOwnProperty("responseJSON")
&& xhr.responseJSON.hasOwnProperty("Message")) {
let data = settings.hasOwnProperty("data") ? JSON.parse(settings.data) : null;
switch (xhr.responseJSON.Message) {
// Handle errors
}
}
});
And now I would like somewhere to chain the promise returned by $.ajaxCall (that is the promise object of the deferred object returned by $.ajax):
$.ajaxCall({
url: "WebServices/Workspace_Ajax.asmx/WebMethod",
data: JSON.stringify(DataObject)
})
.then(successAjax, function() {
console.log("Rejected, ajax call failed!");
});
But the reject handler of then is not called, while the $.ajaxError function is well called. I don't understand why the Promise is not rejected (for the case where ajax request works, the Promise is well resolved). What am I missing ?

Uncaught in promise error but getting result from first call

I have two AJAX calls, the second one depends on the first one, so I decided to use promises. I keep getting Uncaught (in promise) abc123 error in console. Note that abc123 is the id I am expecting from the first AJAX call. The second AJAX call never goes inside success function.
var promise = new Promise(function(reject, resolve) {
$.ajax({
url: url1,
dataType: 'json',
success: function (obj1) {
console.log("Got obj1");
resolve(obj1.id);
}
});
});
promise.then((id)=> {
$.ajax({
url: url2,
dataType: 'json',
success: function (obj2) {
console.log("Got obj2");
}
});
});
The structure looks exactly the same as Basic Example. I am really confused about what I am doing wrong.
You mixed up the order of the callback functions: resolve is the first argument, reject is the second, so you when you called the second one (resolve(obj.id)) you actually rejected your promise.
However, notice that you should not use the Promise constructor anyway when dodging jQuery promises - just use Promise.resolve to cast the jQuery promise that $.ajax returns to a native one:
var promise = Promise.resolve($.ajax({
url: url1,
dataType: 'json'
})).then(obj1 => {
console.log("Got obj1");
return obj1.id;
});
promise.then(id => {
return $.ajax({
//^^^^^^ don't forget this
url: url2,
dataType: 'json'
});
}).then(obj2 => {
console.log("Got obj2");
});

jQuery when - wait for multiple success/done callbacks

I´m using $.when to determine, when an array of ajax promises are finished. I encountered, that the moment $.when fires the ajax calls are finished, but their callbacks / done functions aren´t. How can I wait for the callbacks to be finished?
the ajax calls look like this:
$.ajax({
method: 'POST',
url: url,
data: formData,
processData: false,
contentType: false
}).then(
function(data) {
data = JSON.parse(data);
var url = data.url;
obj.set('src', url);
});
and $.when s.th. like this:
$.when(promises).done(function(){
// the values of objs change in the .done function of the request above
// but when the following ajax got fired, the values haven´t changed yet
if(DEV) console.info('send Json: ', objs);
$.ajax({
method: "POST",
url: url,
data: objs
});
});
I would do this by using jQuery v1.8 or later and using then rather than fail and done and success/failure callbacks:
var promise1 = $.ajax({
/* ...params...*/
}).then(
function(data) {
// Handle success; if you modify what you get, `return` it
// and it will get propagated
return /*...`data` or updated `data` as appropriate...*/;
},
function(error) {
// Handle failure
}
);
var promise2 = /*...*/;
Then
$.when(promise1, promise2).then(
function(data) {
// Handle overall success; this will be called after the
// earlier `then` callbacks on each request
},
function(error) {
// Handle failure
}
);
Live example on jsFiddle (sadly, Stack Snippets don't provide any ajax features); full source below
Note that $.when expects discrete arguments, not an array. If you really have an array, then:
$.when.apply($, promises).then(
// ...
);
...or of course on a modern JavaScript engine:
Promise.all(promises).then(
// ...
);
Full source of the fiddle above, which uses jQuery v2.2.4:
log("Starting");
var promise1 = $.ajax({
url: "/echo/json/"
}).then(
function(data) {
// Handle success; if you modify what you get, `return` it
// and it will get propagated
log("Got promise1's response, returning 'p1'");
return 'p1';
},
function(error) {
// Handle failure
}
);
var promise2 = $.ajax({
url: "/echo/json/"
}).then(
function(data) {
// Handle success; if you modify what you get, `return` it
// and it will get propagated
log("Got promise2's response, returning 'p2'");
return 'p2';
},
function(error) {
// Handle failure
}
);
$.when(promise1, promise2).then(
function(result1, result2) {
// Handle overall success; this will be called after the
// earlier `then` callbacks on each request
log("Both are done", result1, result2);
},
function(error) {
// Handle failure
}
);
function log() {
// Old-fashioned to stay ES5 compatible
$("<pre>").text(Array.prototype.join.call(arguments, ", ")).appendTo(document.body);
}
Can you chain your promises? With something like this (not tested):
$.ajax({
method: 'POST',
url: url,
data: formData,
processData: false,
contentType: false
}).then(
function(data) {
data = JSON.parse(data);
var url = data.url;
obj.set('src', url);
// return your promises (if possible, I don't know where they come from)
return promises
}).then(
function() {
if(DEV)
console.info('send Json: ', objs);
$.ajax({
method: "POST",
url: url,
data: objs
});
});
use this
$.ajax({
method: 'POST',
url: url,
data: formData,
processData: false,
contentType: false,
success: function(data){/* to handle success response */},
error: function(error){/* to handle error response */},
complete: function(data){/* to handle the response success or error*/}
});
the data = JSON.parse(data); in your ajax function is not mutating the data object but create a new data object, you need to return it back so the caller can grab it
Try it like this,
function getData(){
return $.ajax({
method: 'POST',
url: url,
data: formData,
processData: false,
contentType: false
}).then(
function(data) {
data = JSON.parse(data);
var url = data.url;
obj.set('src', url);
return data;
});
}
var data = $.when(promises).done(getData);

How to pass arguments in promise

I am using promise like this:
var restClient = {
serveRequest: function(rUrl, type, body, rHeaders, rAsync, callback) {
var promise = jQuery.ajax({
url: rUrl,
type: type,
data: body,
headers: rHeaders,
async: rAsync,
contentType: "text/plain",
dataType: "json"
});
promise.then(onSuccess, onError);
},
onSuccess: function(data) {
callback(data);
},
onError: function(msg) {
console.log(msg.responseText);
}
}
How can I pass arguments (callback) in promise.then onSuccess? I want to use that in onSuccess method later.
I am using promise like this
Well, first of all, you shouldn't. The purpose of promises is to be returned as results from asynchronous functions, so that you don't need callback parameters any more. You'd better just do
var restClient = {
serveRequest: function(rUrl, type, body, rHeaders, rAsync) {
var promise = jQuery.ajax({
url: rUrl,
type: type,
data: body,
headers: rHeaders,
async: rAsync,
contentType: "text/plain",
dataType: "json"
});
return promise;
}
};
and let the caller of restClient.serveRequest(…) invoke .then(…).
How can I pass arguments (callback) in promise.then onSuccess?
You don't need that onSuccess. Just directly use
promise.then(callback, function(msg) {
console.log(msg.responseText);
});
I want to use that in onSuccess method later.
You cannot. It tries to use callback, but that is a parameter local to the serveRequest method - so onSuccess could at most be a local function in there, but not a method on its own.

Provide a default 'fail' method for a jQuery deferred object

I am writing a Javascript API client using jQuery. My top level request method looks like this:
function request(method, uri, params, proxies) {
var deferred = $.Deferred();
$.ajax({
data: method == 'GET' ? params : JSON.stringify(params),
contentType: 'application/json',
dataType: 'json',
url: api.root + uri,
type: method,
xhrFields: {
withCredentials: true
}
}).done(function(body) {
deferred.resolveWith(this, [body.data]);
}).fail(function(xhr) {
deferred.rejectWith(this, [xhr]);
});
return deferred.promise();
},
How can I have a default fail handler for my returned deferred? That is, if the deferred has no other handlers attached to it's fail condition, call a default handler.
I want to do this to have global exception handling in my application, except for the parts that have a specific handling (and will define their own fail handler on the deferred).
So, the cleanest way to use jQuery ajax in an API as of 2016 is to return a promise. But, you cannot determine whether a caller has attached an error handler or not to the promise.
So, what I'd suggest is that you just add a new argument to your function that tells the function to NOT apply the default error handling because the caller will take care of the error handling. And, I'd suggest you avoid the promise anti-pattern by just using the existing promise $.ajax() already returns rather than creating your own deferred:
function request(method, uri, params, proxies, skipDefaultErrorHandling){
// default error handling will be used if nothing is passed
// for skipDefaultErrorHandling
var p = $.ajax({
data: method=='GET'?params:JSON.stringify(params),
contentType: 'application/json',
dataType: 'json',
url: api.root + uri,
type: method,
xhrFields: {
withCredentials: true
}
});
if (!skipDefaultErrorHandling) {
// apply default error handling
p = p.then(null, function(jqXHR, textStatus, errorThrown) {
// put here whatever you want the default error handling to be
// then return the rejection with the various error parameters available
return $.Deferred().reject([jqXHR, textStatus, errorThrown]);
});
}
return p;
};
Then, the caller just decides whether to apply their own error handling or not:
request(...).then(function(data) {
// success code here
});
Or, you can go with a non-promise failHandler callback that you pass in and your default error handling looks to see if that failHandler was passed in or not. This is hybrid of promises and callbacks and is not something I would normally choose to architect, but since your question asks for something that promises do not support, this is one of achieving that:
function request(method, uri, params, proxies, failHandler){
// default error handling will be used if nothing is passed
// for skipDefaultErrorHandling
var p = $.ajax({
data: method=='GET'?params:JSON.stringify(params),
contentType: 'application/json',
dataType: 'json',
url: api.root + uri,
type: method,
xhrFields: {
withCredentials: true
}
});
// apply default error handling
p = p.then(null, function(jqXHR, textStatus, errorThrown) {
if (failHandler) {
// call passed in error handling
failHandler.apply(this, arguments);
} else {
// do your default error handling here
}
// then keep the promise rejected so the caller doesn't think it
// succeeded when it actually failed
return $.Deferred().reject([jqXHR, textStatus, errorThrown]);
});
return p;
};

Categories