Working with Ajax Promises / Deferred - javascript

I am trying to get an Ajax promise using the code below. Because my function makes another ajax call before initiating the actual one , for getting the authKey, The promise (that should have been returned) from the actual call is null, & I cannot use .then() on it because I think I am not getting anything in return from it. I am not sure why.
What am I doing wrong here? Is there any other way to go about this. I call getAjaxPromise() like mentioned below but get null in return:
getAjaxPromise(myUrl, true, myType, myContentType, mySuccessFunction, myFailureFunction,
myData, true)
.then(function(data) //.then() gives undefined-null error
{
//Do something with the data returned form actual Ajax call.
});
self.getAjaxPromise = function(url, async, type, contentType, successCallback,
errorCallback, data, isSecureCall)
{
if (isSecureCall) {
var tokenPromise = getTokenPromiseFromServer(); //Another Ajax call to get latest token from service
tokenPromise.then(function(tokenData) { //This then runs fine
return $.ajax({
beforeSend: function(request) {
request.setRequestHeader("authKey", tokenData.key);
},
url: url,
async: async,
type: type,
contentType: contentType,
success: successCallback, //Success callback runs fine, then() does not
error: errorCallback, //Error callback runs fine, then() does not
data: JSON.stringify(data)
});
});
} else { //Just one ajax call
return $.ajax({
beforeSend: function(request) {
request.setRequestHeader("authKey", "anonymous");
},
url: url,
async: async,
type: type,
contentType: contentType,
success: successCallback,
error: errorCallback,
data: JSON.stringify(data)
});
});
}
};

you forgot to return the getTokenPromiseFromServer
if isSecureCall is true your function return null
self.getAjaxPromise = function(url, async, type, contentType, successCallback,
errorCallback, data, isSecureCall)
{
if (isSecureCall) {
return getTokenPromiseFromServer().then(function(tokenData) {
return $.ajax({
beforeSend: function(request) {
request.setRequestHeader("authKey", tokenData.key);
},
url: url,
async: async,
type: type,
contentType: contentType,
success: successCallback, //Success callback runs fine, then() does not
error: errorCallback, //Error callback runs fine, then() does not
data: JSON.stringify(data)
});
});
} else { //Just one ajax call
return $.ajax({
beforeSend: function(request) {
request.setRequestHeader("authKey", "anonymous");
},
url: url,
async: async,
type: type,
contentType: contentType,
success: successCallback,
error: errorCallback,
data: JSON.stringify(data)
});
});
}
};

You had forgot to return the promise inside the if statement, you are return it only on else, the fixed code below:
self.getAjaxPromise = function(url, async, type, contentType, successCallback,
errorCallback, data, isSecureCall) {
if (isSecureCall) {
var tokenPromise = getTokenPromiseFromServer(); //Another Ajax call to get latest token from service
tokenPromise.then(function(tokenData) {
return $.ajax({
beforeSend: function(request) {
request.setRequestHeader("authKey", tokenData.key);
},
url: url,
async: async,
type: type,
contentType: contentType,
success: successCallback, //Success callback runs fine, then() does not
error: errorCallback, //Error callback runs fine, then() does not
data: JSON.stringify(data)
});
});
return tokenPromise;
} else { //Just one ajax call
return $.ajax({
beforeSend: function(request) {
request.setRequestHeader("authKey", "anonymous");
},
url: url,
async: async,
type: type,
contentType: contentType,
success: successCallback,
error: errorCallback,
data: JSON.stringify(data)
});
});
}
};

You forgot to return tokenPromise
you must return it from first if
if (isSecureCall) {
var tokenPromise = getTokenPromiseFromServer(); //Another Ajax call to get latest token from service
// ...
return tokenPromise;
}

Related

How to use async/await for getting data through sharepoint online?

I am able to get some data in SharePoint online using rest and js, and it is solving my purpose also but then i am using async: false to make it synchronous, which i think is not the recommended way. so when i looked for alternative solution, i found out about async/await. Is it possible to use async/await in the code below? Please suggest.
function GetUserProperties(user) {
//getting user properties for a user
var url = _spPageContextInfo.webAbsoluteUrl + "/_api/SP.UserProfiles.PeopleManager/GetPropertiesFor(accountName=#v)?#v=%27i%3A0%23.f|membership|" + user + "%27";
$.ajax({
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
url: url,
success: function(data) {
successUsersInfo(data);
},
error: function(data1) {
alert("ERROR");
}
});
}
function successUsersInfo(data) {
// logic to call data
secondFunction(); //then i am calling another function
}
function secondFunction() {
$.ajax({
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
url: url,
async: false,
success: function(data) {
//logic to get data
},
error: function(data1) {
alert("ERROR");
}
});
//now my third function depends on the values of second data
//and i am using async:false, to make it synchronous
thirdFunction();
}
function thirdFunction() {
//logic to use second function data since my third function is dependent on second function
}
Use $.Deferred() in such senarios, which will help to chain the functions and you will be able to use then operator
function GetUserProperties(user) {
var deferred = $.Deferred();
var url = _spPageContextInfo.webAbsoluteUrl + "/_api/SP.UserProfiles.PeopleManager/GetPropertiesFor(accountName=#v)?#v=%27i%3A0%23.f|membership|" + user + "%27";
$.ajax({
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
url: url,
success: function (data) {
deferred.resolve(data);
},
error: function (data1) {
alert("ERROR");
}
});
return deferred.promise();
}
function secondFunction() {
var deferred = $.Deferred();
$.ajax({
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
url: url,
async: false,
success: function (data) {
deferred.resolve(data);
},
error: function (data1) {
alert("ERROR");
}
});
return deferred.promise();
}
function thirdFunction() {
var deferred = $.Deferred();
$.ajax({
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
url: url,
async: false,
success: function (data) {
deferred.resolve(data);
},
error: function (data1) {
alert("ERROR");
}
});
return deferred.promise();
}
Now you can call these function as follows
GetUserProperties("uerid")
.then(function (secondFuncData)
{
secondFunction(secondFuncData)
.then(function (thirdFuncData)
{
thirdFuncData(thirdFuncData)
.then(function (finalData)
{
console.log(finalData);
})
})
})
Function will start with var deferred = $.Deferred(); and end with return deferred.promise();. And return the data in success using deferred.resolve(data);
$.ajax already returns a promise. It's jQuery promise that isn't necessarily Promise/A+ compliant (this was fixed in jQuery 3), but it is thenable, so it can be handled by await naturally. $.ajax requires no callbacks to return a promise:
async function GetUserProperties(user) {
...
let result = await $.ajax({
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
url: url
});
...
}

Getting Data from Ajax request displayed

I've already read this article How do I return the response from an asynchronous call? However I couldn't come up with a solution.
I'm doing an ajax request
function getdata(url)
{
console.log('Started');
jQuery.ajax({
type: "GET",
url: "http://myserver.com/myscript.php",
dataType: "json",
error: function (xhr) {
console.log('Error',xhr.status);
},
success: function (response) {
console.log('Success',response);
}
});
}
And Console displays everything fine but when I say
var chinese = getdata();
to get the data. I keep getting:
Uncaught TypeError: Cannot read property 'length' of undefined error for this line
var text = chinese[Math.floor(Math.random()*chinese.length)];
Can anybody help me here?
The problem is that you are using an asynchronous method expecting a synchronous result.
Therefore you should use the code in the result of the asynchronous call like the following:
function getdata(url) {
console.log('Started');
jQuery.ajax({
type: 'GET',
url: url,
dataType: 'json',
error: function(xhr) {
console.log('Error', xhr.status);
},
success: function(chinese) {
var text = chinese[Math.floor(Math.random()*chinese.length)];
// Do something else with text
}
});
}
getData('http://myserver.com/myscript.php');
I hope it helps :)
The error you get is because of the asynchronous nature of the call. I suggest you to assign the value after you get the success response from the API like below.
var chinese = getdata();
Then the function getdata() will be like
function getdata(url)
{
console.log('Started');
jQuery.ajax({
type: "GET",
url: "http://myserver.com/myscript.php",
dataType: "json",
error: function (xhr) {
console.log('Error',xhr.status);
},
success: function (response) {
initChinese(response.data);
}
});
}
And create a function initChinese() like
var text;
function initChinese(chinese){
text = chinese[Math.floor(Math.random()*chinese.length)];
}
You can also declare the text variable in global scope and then assign the value to text variable inside the success function without having to create a new function initChinese.
The problem is your getdata function does not return anything. In your getdata function you're doing a ajax request, which is an asynchronous request. So the data you're requesting won't, and can't be returned with your getdata function.
But you will have the requested data in your success function:
function getdata(url)
{
console.log('Started');
jQuery.ajax({
type: "GET",
url: "http://myserver.com/myscript.php",
dataType: "json",
error: function (xhr) {
console.log('Error',xhr.status);
},
success: function (response) {
console.log('Success',response);
var text = response[Math.floor(Math.random()*response.length)];
}
});
}
As I'm not able to test your code, you've to debug the rest on your own. But the response variable will be most likely your "chinese" variable.
You could try using callbacks or you could look at Promises.
The idea with callbacks is that you pass a function that is run after the ajax request is finished. That callback can accept a parameter, in this case the response.
Using callbacks:
function getData(url, successCallback, errorCallback) {
console.log('Started');
jQuery.ajax({
type: "GET",
url: url,
dataType: "json",
error: function(xhr) {
errorCallback(xhr.status);
},
success: function(response) {
successCallback(response);
}
});
}
var chinese;
getData("http://myserver.com/myscript.php", function(response) {
chinese = response; // you can assign the response to the variable here.
}, function(statusCode) {
console.error(statusCode);
});
Using Promises (< IE11 doesn't support this):
function getData(url) {
return new Promise(function(resolve, reject) {
console.log('Started');
jQuery.ajax({
type: "GET",
url: url,
dataType: "json",
error: function(xhr) {
reject(xhr.status);
},
success: function(response) {
resolve(response);
}
});
});
}
var chinese;
getData("http://myserver.com/myscript.php").then(function(response) {
chinese = response;
console.log(chinese);
}, function(statusCode) {
console.error(statusCode);
});

How to force $ajax to wait for data and assign these to a variable?

I have trouble async disable ajax. I have the following code:
function GetDataFromUninorte() {
link="http://www.uninorte.edu.co/documents/71051/11558879/ExampleData.csv/0e3c22b1-0ec4-490d-86a2-d4bc4f512030";
var result=
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
async: false,
dataType: 'json',
success: function(response) {
console.log("Inside: " + response);
}
}).responseText;
console.log("Outside: "+result);
return result;
}
And I get the following result:
"Outside" always runs first
As you can see, "Outside" always runs first and the result is undefined and can not process data.
I have already tried
When ... Then
Async = false
passing data as parameters I / O function
and other things, but nothing
:/
... Beforehand thank you very much
(I am not a native english speaker, I apologize if I do not write well)
[Solved]
Maybe is not the best form, but in the "success:" statement I call a function that receive the ajax response and trigger the rest of the process, in this way I not need store the in a variable and the asynchrony not affect me.
Use can use callbacks, you can read more here
function GetDataFromUninorte(successCallback, errorCallback) {
link="http://www.uninorte.edu.co/documents/...";
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
async: false,
dataType: 'json',
success: successCallback,
error: errorCallback
});
}
function mySuccessCallback(successResponse) {
console.log('callback:success', successResponse);
}
function myErrorCallback(successResponse) {
console.log('callback:success', successResponse);
}
GetDataFromUninorte(mySuccessCallback, myErrorCallback);
Or you can use promises (bad support in IE browsers)
function GetDataFromUninorte() {
return new Promise(function(resolve, reject) {
link="http://www.uninorte.edu.co/documents/...";
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
async: false,
dataType: 'json',
success: resolve,
error: reject
});
});
}
GetDataFromUninorte()
.then(function(successResponse){
console.log('promise:success', successResponse);
}, function(errorResponse){
console.log('promise:error', errorResponse);
});
AJAX being asynchronous by nature, you need to pass callback, which will be called when the ajax response is received. You may then access responseText from the xhr object.
You can also you jQuery Deferred and promise to get around your problem like below:
function GetDataFromUninorte() {
var defObject = $.Deferred(); // create a deferred object.
link="http://www.uninorte.edu.co/documents/71051/11558879/ExampleData.csv/0e3c22b1-0ec4-490d-86a2-d4bc4f512030";
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
async: false,
dataType: 'json',
success: function(response) {
console.log("Inside: " + response);
defObject.resolve(response); //resolve promise and pass the response.
}
});
return defObject.promise(); // object returns promise immediately.
}
and then:
var result = GetDataFromUninorte();
$.when(result).done(function(response){
// access responseText here...
console.log(response.responseText);
});
You should avoid making AJAX synchronous by setting async:false as that will block further interactions on the User Interface.
Use this:
function GetDataFromUninorte() {
link="http://www.uninorte.edu.co/documents/71051/11558879/ExampleData.csv/0e3c22b1-0ec4-490d-86a2-d4bc4f512030";
var result=
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
**timeout: 2000,**
async: false,
dataType: 'json',
success: function(response) {
console.log("Inside: " + response);
}
}).responseText;
console.log("Outside: "+result);
return result;
}

jQuery promise with function

I'm trying to make global ajax handler. so first let me show you the function
var data = {
test : 1
}
$.when( $.ajax({
type: 'POST',
url: ajaxurl,
data : data,
dataType: "json",
success: function(data) {
console.log('first me')
}
})
).then(function( data, textStatus, jqXHR ) {
console.log('then me')
});
this way it works.
and outputs
first me
then me
But I want this ajax to be a function
So this is how I'm trying to make it.
var data = {
test : 1
}
$.when(globalAjax(data)).then(function( data, textStatus, jqXHR ) {
console.log('then me')
});
function globalAjax(data) {
$.ajax({
type: 'POST',
url: ajaxurl,
data : data,
dataType: "json",
success: function(data) {
console.log('first me')
}
})
}
this way console outputs then me and then first me.
How to ask to wait ajax inside a function?
You need to return a promise in globalAjax:
function globalAjax(data) {
return $.ajax({
type: 'POST',
url: ajaxurl,
data : data,
dataType: "json",
success: function(data) {
console.log('first me')
}
});
}
And you don't need to use the $.when function:
globalAjax(data).then(function(data, ...) { ... });
$.when is, mainly, to wait for the completion of two or more deferreds or promises.
function globalAjax(data) {
return $.ajax({
type: 'POST',
url: ajaxurl,
data : data,
dataType: "json",
success: function(data) {
console.log('first me')
}
});
}
you need to return a promise from your function.
$.ajax({
type: 'POST',
url: ajaxurl,
data : data,
dataType: "json",
success: function(data) {
console.log('first me')
}
}).then(function( data, textStatus, jqXHR ) {
console.log('then me')
});
You dont need when $.ajax already returns a promise.
You need to return the ajax promise from globalAjax so that it can be passed to $.when
function globalAjax(data) {
return $.ajax({
type: 'POST',
url: ajaxurl,
data: data,
dataType: "json",
success: function (data) {
console.log('first me')
}
})
}
Demo: Problem, Solution
$.when()
If a single argument is passed to jQuery.when and it is not a Deferred
or a Promise, it will be treated as a resolved Deferred and any
doneCallbacks attached will be executed immediately.
In your case since there is no return from the method, it will pass undefined to $.when which is causing the behavior
since a promise is returned there is no need to use $.when()
globalAjax(data).then(function (data, textStatus, jqXHR) {
console.log('then me')
});
Demo: Fiddle

Generic $.ajax() call function for resusability

I am creating a application where I have lot of ajax calls to a remote server and use them extensively. As the code is almost same in all calls, I want to create a new function which I can reuse. I am struck up in defining the parameter structure for the "data" parameter. I will explain below my problem.
Sample of my current ajax call is provided below.
Current Call Sample:
$.ajax({
beforeSend: function() {
$.mobile.loading('show');
},
complete: function() {
$.mobile.loading('hide');
},
type: 'GET',
url: 'http://localhost/test-url/',
crossDomain: true,
data: {appkey: '1234567', action: 'action1','name':'me'},
dataType: 'jsonp',
contentType: "application/javascript",
jsonp: 'callback',
jsonpCallback: 'mycallback',
async: false,
error: function() {
//some operations
},
success: function(data) {
//some operations
}
});
The re-usable function that I have created:
function newAjax(parm, successCallback, errorCallback) {
$.ajax({
beforeSend: function() {
$.mobile.loading('show');
},
complete: function() {
$.mobile.loading('hide');
},
type: 'GET',
url: 'http://localhost/test-url',
crossDomain: true,
data: {appkey: '1234567', parm: parm},
dataType: 'jsonp',
contentType: "application/javascript",
jsonp: 'callback',
jsonpCallback: 'mycallback',
async: false,
success: function() {
successCallback();
},
error: function() {
errorCallback();
}
});
}
Question:
I will be passing the the parameters for the ajax call via "parm" parameter. I want the data value to be directly added to the parent "data" parameter. And not as a sub-object of data. The appKey remains same across all calls and so I keep it in the actual function.
I want both the success and error callback functions to be optional. If not provided they should be ignored.
You can use the jQuery.extend method to combine two or more objects together.
data: jQuery.extend({appkey: '1234567'}, parm),
You can check that you were actually passed functions for successCallback and errorCallback using typeof var === 'function';
success: function () {
if (typeof successCallback === 'function') {
successCallback();
}
},
error: function () {
if (typeof errorCallback === 'function') {
errorCallback();
}
}
... although it might be nicer if you just returned the Promise created by the AJAX request, and let the caller add their success, error handlers if they wanted;
function newAjax(parm) {
return jQuery.ajax({
/* as before, but without success and error defined */
});
}
... then:
newAjax().done(function () {
// Handle done case
}).fail(function () {
// Handle error case.
});
If a caller doesn't want to add an error handler, they just don't call fail();
newAjax().done(function () {
// Handle done case
});

Categories

Resources