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 ?
Related
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");
});
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
});
}
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;
};
I've seen .when() and .then() used directly with .ajax calls in jquery to delay the execution of a callback function until the ajax is done. What I'm having trouble with is doing the same for functions that are not ajax calls themselves, but contain an ajax function. I've got the following chunk of code:
$(function() {
$('.document').on('click', '.ajax', ajaxFunction);
});
function ajaxFunction(e) {
e.preventDefault();
// ajax request
$.ajax({
async: true,
cache: false,
type: 'post',
url: '/echo/html/',
data: {
html: '<p>This is echoed the response in HTML format</p>',
delay: 1
},
dataType: 'html',
beforeSend: function() {
console.log('Fired prior to the request');
},
success: function(data) {
console.log('Fired when the request is successfull');
$('.document').append(data);
},
complete: function() {
console.log('Fired when the request is complete');
}
});
console.log('hello world!');
}
function defferedFunction(d){
$.when(ajaxFunction(e)).then(alert('hi mom!'))
}
My goal was to fire the alert ('hi mom!') when the contents of the ajaxFunction function were complete, i.e. when the ajax was done and 'hello world!' had logged to the console. However, the alert never comes up.
The problem, so far as I can tell, is that the container function doesn't actually return a promise, and hence the .then() section never fires. How can I modify this code to return a promise when all of the internal code, including the ajax, is finished?
I'd prefer to continue using the .when() / .then() pattern rather than manually including a callback in ajaxFunction.
A fiddle of the above example is here.
You can return a promise
function ajaxFunction(e) {
e.preventDefault();
// ajax request
return $.ajax({ // return promise
async: true,
cache: false,
type: 'post',
url: '/echo/html/',
A couple of things. Like #pXL stated you need to return the promise. Also in your fiddle you need to pass the (d) parameter from your defferedFunction to your ajaxFunction. Finally change your .then
to .done(function(a){});
http://jsfiddle.net/mq4Sj/5/
$(function() {
$('.document').on('click', '.ajax', defferedFunction);
});
function defferedFunction(e){
$.when(ajaxFunction(e)).done(function(d){
alert(d); // ->> response from server.
})
}
I figured out that I can do this by creating a deferred event for the whole function, a deferred event for the non-ajax behavior that I want to capture, resolving the second deferred event after the non-ajax stuff is done, and then using a $.when() to capture when both the deferred object returned by the ajax call is resolved and when the deferred object I created for the non-ajax stuff is done, and then using a .then() to resolve the deferred object for the whole function.
It looks like this, all put together:
$(function() {
$('.document').on('click', '.ajax', defferedFunction);
});
function ajaxFunction(e) {
e.preventDefault();
// ajax request
var ajaxDeferred = $.ajax({
async: true,
cache: false,
type: 'post',
url: '/echo/html/',
data: {
html: '<p>This is echoed the response in HTML format</p>',
delay: 1
},
dataType: 'html',
beforeSend: function() {
console.log('Fired prior to the request')
},
success: function(data) {
console.log('Fired when the request is successfull');
$('.document').append(data);
},
complete: function() {
console.log('Fired when the request is complete');
}
})
var newDeferred = $.Deferred()
var timeoutDeferred = $.Deferred()
setTimeout(function(){
console.log('hello world!')
timeoutDeferred.resolve()
}, 2000)
$.when(timeoutDeferred, ajaxDeferred).then(function(){
newDeferred.resolve()
}
);
return newDeferred;
}
function defferedFunction(e){
$.when(ajaxFunction(e)).done(function(){alert('all done!')})
}
Let's say for example, I have the following javascript function that returns a boolean:
function CallWebServiceToUpdateSessionUser(target, user)
{
var dataText = { "jsonUser": JSON.stringify(user) };
$.ajax({
type: "POST",
url: target,
data: JSON.stringify(dataText),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response)
{
return true;
},
failure: function (msg)
{
return false;
}
});
}
and the target function on the server that is being called could take up to... 15 seconds to respond.
How do I guarantee that this function will not exit until after the server call has been completed? Or, how can I guarantee that who ever is calling this function will get a true/false and not an undefined?
NOTE:
I've seen people use async: false but that hangs the UI which I do not want.
See http://api.jquery.com/jQuery.ajax/. You need to do an AJAX request with async: true to your parameters. You will then need to edit your code so the code that executes after a successful request is inside the successful block.