Manipulate data from an async call - javascript

I have two functions,
function getRequest(url, api_key, callback) {
$.ajax({
url: url,
contentType: 'application/json',
type: 'get',
beforeSend: function(xhr){
xhr.setRequestHeader('Authorization', 'Bearer ' + api_key);
},
success: function(response) {
callback(response);
},
error: function(error) {
console.log(error);
document.getElementById("droplets").textContent = error;
}
});
}
function getDroplets(url, api_key) {
var request = getRequest(url, api_key, function(response) {
var droplets = response.droplets;
var numDroplets = droplets.length;
return {
droplets: droplets,
numDroplets: numDroplets
};
});
alert(request);
}
I want to have another function, let's call it listDroplets, that will call getDroplets() and manipulate the data returned from it. I'm not sure how to do this because getDroplets has an asynchronous call within it.
EDIT: I have tried the following, but it still doesn't work.
async function listDroplets() {
await getDroplets(api_url, api_key);
alert(request.numDroplets);
}

Here are how your functions could return promise like objects that you can use in an async await function:
function getRequest(url, api_key, callback) {
//to escape terrible jQuery Deferred and comfortably continue in Promise land
// you can do
// const deferred = $.ajax(...); return Promise.resolve(deferred)
return $.ajax({//return promise like object
url: url,
contentType: 'application/json',
type: 'get',
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer ' + api_key);
}
});
}
function getDroplets(url, api_key) {
return getRequest(url, api_key)//return promise like object
.then(function (response) {//
var droplets = response.droplets;
var numDroplets = droplets.length;
return {
droplets: droplets,
numDroplets: numDroplets
};
})
.catch(function (error) {//implement error if something goes wrong
console.log(error);
document.getElementById("droplets").textContent = error;
});
}
async function listDroplets() {
//depending on how old your jQuery is you may want to do this:
// await Promise.resolve(getDroplets(api_url, api_key));
const request = await getDroplets(api_url, api_key);
//note that if something goes wrong then request is undefined (depending on jQuery version)
alert(request.numDroplets);
}

Related

How to get multiple ajax responses in one function

I don't know if it's possible, but i'm trying to get multiple ajax responses and access it's values in another function.
I actually get the responses (twice each), but i'm not able to return the responses individual values.
JSFiddle
function firstResponse() {
const response1 = $.ajax({
url: 'https://cors-anywhere.herokuapp.com/http://api.icndb.com/jokes/random',
method: 'GET',
contentType: 'application/json',
});
response1.done(function(response1) {
test(response1);
})
}
function secondResponse() {
const response2 = $.ajax({
url: 'https://cors-anywhere.herokuapp.com/https://official-joke-api.appspot.com/random_joke',
method: 'GET',
contentType: 'application/json',
});
response2.done(function(response2) {
test(response2);
})
}
firstResponse();
secondResponse();
function test(response1, response2) {
console.log('Response 1', response1);
console.log('Response 2', response2);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
There are various ways to achieve that. I personally would go with promises.
function firstResponse() {
return $.ajax({
url: 'https://cors-anywhere.herokuapp.com/http://api.icndb.com/jokes/random',
method: 'GET',
contentType: 'application/json'
});
}
function secondResponse() {
return $.ajax({
url: 'https://cors-anywhere.herokuapp.com/https://official-joke-api.appspot.com/random_joke',
method: 'GET',
contentType: 'application/json'
});
}
function test() {
Promise.all([
firstResponse(),
secondResponse()
]).then(result => {
console.log(result);
});
}
test();
In the test function you call a Promise.all which waits for all the individual promises to be resolved and outputs the result as an array in the order the of the promises passed to it at the time of calling.
let urls = ['https://cors-anywhere.herokuapp.com/http://api.icndb.com/jokes/random',
'https://cors-anywhere.herokuapp.com/https://official-joke-api.appspot.com/random_joke'];
let structure = {
method: 'GET',
contentType: 'application/json',
};
async function first() {
try {
const response = await $.ajax({
url: urls[0],
structure,
});
return response;
} catch(error) {
// Error
}
}
async function second() {
try {
const response = await $.ajax({
url: urls[1],
structure,
});
return response;
} catch(error) {
// Error
}
}
async function test() {
let response = await ('s')
return response
}
first()
.then(() => second());
Ajax calls are asynchronous so if you want to handle the two results in one function you have to do a counter yourself, something like this for the simplest kind:
function firstResponse() {
const response1 = $.ajax({
url: 'https://cors-anywhere.herokuapp.com/http://api.icndb.com/jokes/random',
method: 'GET',
contentType: 'application/json',
});
response1.done(function(response1) {
test("response1", response1);
})
}
function secondResponse() {
const response2 = $.ajax({
url: 'https://cors-anywhere.herokuapp.com/https://official-joke-api.appspot.com/random_joke',
method: 'GET',
contentType: 'application/json',
});
response2.done(function(response2) {
test("response2", response2);
})
}
var responses = [];
firstResponse();
secondResponse();
function test(index, data) {
responses[index] = data;
if (Object.keys(responses).length === 2) processResponses();
}
function processResponses() {
console.log(responses);
}
There are various more advanced way to handle it, like using async/await or something, but this should get your work done without much modification to your existing code.
UPDATE: for the async/await way which is my preferred way of doing things nowadays:
(async () => {
const response1 = await $.ajax({
url: 'https://cors-anywhere.herokuapp.com/http://api.icndb.com/jokes/random',
method: 'GET',
contentType: 'application/json',
});
const response2 = await $.ajax({
url: 'https://cors-anywhere.herokuapp.com/https://official-joke-api.appspot.com/random_joke',
method: 'GET',
contentType: 'application/json',
});
console.log(response1);
console.log(response2);
})();

ReactJs Promise + Ajax Return Value

I have a function which uses jquery to call API and get a result. My API end is programmed to return the number "19" just for testing.
export function clientAdd(data) {
return (dispatch) => {
return $.ajax({
url: "http://api.example.com/client/add/",
headers: {'AUTHORIZATION': `${sessionStorage.jwt}`},
type: 'POST',
cache: false,
data: data,
dataType: 'json',
success: function (data) {
let redirectUrl = '/client/' + data
return redirectUrl';
},
error: function(xhr, status, err) {
if (xhr.status === 401) {
sessionStorage.removeItem('jwt');
return '/signin';
}
console.log('xhr',xhr.responseText);
console.log('status',status);
console.log('err',err);
return dispatch({type: GET_CLIENT_FAIL, err});
}
})
}
}
Then in my component, upon clicking on the submit button, it will call the onSave function as follows
onSave(event) {
//event.preventDefault();
this.props.actions.clientAdd(this.state.credentials).then((result) => {
return this.setState({redirect: true, newCustomerId: result})
}).catch((result) => {
return this.setState({redirect: false, errorMessage: result})
});
}
Where the result is supposed to be the redirectUrl or ErrorMessage.
However, I'm keep getting the number 19 which is returned by my API.
I read online if I want to use promise in my component, i have to add return infront of $.ajax, if not "then" will be undefined.
What you can do is, create your own promise and put the ajax call inside it
Then call resolve and pass data that you want when then is called
resolve(data_passed_to_then)
Like this :
return new Promise((resolve,reject) => {
$.ajax({
...
success: function (data) {
let redirectUrl = '/client/' + data
resolve(redirectUrl);
},
error: function(xhr, status, err) {
...
// return dispatch({type: GET_CLIENT_FAIL, err});
reject(err);
}
})
})

How to chain multiple separate JavaScript functions

I know similar questions have been asked before but none of the examples make sense to me. (Any I have found have failed to explain the basics for me with the clarity I need.)
I have four AngularJS functions. Each calls a REST service and does stuff that is unrelated to any of the other functions. E.g.
$scope.step1 = function() { $http({
method: 'GET',
url: "http://www/end/point",
cache: true,
headers: { "Accept": "application/jsonp;odata=verbose" }
}).success(function (data, status, headers, config) {
$scope.step1data = data;
}).error(function (data, status, headers, config) {
$scope.logError(data);
});};
I would like to call the four functions in sequence
$scope.step1
$scope.step2
$scope.step3
$scope.step4
And catch any errors encountered.
I have narrowed the code to the below but it does not work for me. Any help would be greatly appreciated.
$scope.step1().then(function() {
$scope.step2();
}).then(function() {
$scope.step3();
}).then(function() {
$scope.step4();
}).catch(function(e) {
console.log(e);
});
You need to return the promise from each step function to your then() callback so that its resulting promise waits for that promise:
$scope.step1().then(function() {
return $scope.step2();
})...
First, change your step1, step2, step3 and step4 to return promises like below:
$scope.step1 = function() {
return $http({
method: 'GET',
url: "http://www/end/point",
cache: true,
headers: { "Accept": "application/jsonp;odata=verbose" }
})};
$scope.step2 = function() {
return $http({
method: 'GET',
url: "http://www/end/point",
cache: true,
headers: { "Accept": "application/jsonp;odata=verbose" }
})};
$scope.step3 = function() {
return $http({
method: 'GET',
url: "http://www/end/point",
cache: true,
headers: { "Accept": "application/jsonp;odata=verbose" }
})};
$scope.step4 = function() {
return $http({
method: 'GET',
url: "http://www/end/point",
cache: true,
headers: { "Accept": "application/jsonp;odata=verbose" }
})};
Then, chain them together like this:
$scope.step1().then(function (step1data) {
$scope.step1data = step1data;
$scope.step2().then(function (step2Data) {
$scope.step2Data = step2Data;
$scope.step3().then(function (step3Data) {
$scope.step3Data = step3Data;
$scope.step4().then(function (step4Data) {
$scope.step4Data = step4Data;
});
});
});
})
You can mix asynchronous functions with any kind of logic that JavaScript offers if you execute your code synchronously via nsynjs. Here is how your code may need to be transformed:
Step 1: Wrap asynchronous function into generic nsynjs-aware wrapper:
// generic function to retrieve url
// ctx is a reference to caller pseudo-thread context
var httpUrl = function(ctx,url,$http) {
var res={};
$http({
method: 'GET',
url: url,
cache: true,
headers: { "Accept": "application/jsonp;odata=verbose" }
})
.success(function (data, status, headers, config) {
res.data = data;
ctx.resume() // tells nsynjs to resume caller function
}).error(function (data, status, headers, config) {
ctx.resume(data) // resume caller function with exception
// or replace with these 2 lines if you don't want exception
// res.error = data;
// ctx.resume()
});
return res;
};
getUrl.nsynjsHasCallback = true; // this tells nsynjs engine that it
// should pause execution and wait until ctx.resume() is called from callback
Step 2. Write your logic as if it was synchronous, and put it into function:
function synchronousCode(param1, param2) {
var step1 = function() {
var data = httpUrl(nsynjsCtx,"nsynjs/examples/data/file1.json").data;
console.log("data is ready at this point:",data);
// do staff this data
return data;
};
var step2 = function() {
var data = httpUrl(nsynjsCtx,"nsynjs/examples/data/file2.json").data;
console.log("data is ready at this point:",data);
// do staff this data
return data;
};
console.log( step1(param1) + step2(param2) ); // do more staff with data
}
Step 3. Run your synchronous code via nsynjs:
nsynjs.run(synchronousCode,{},"value for param1","value for param1",function(){
console.log("Synchronous Code done");
})
More examples here: https://github.com/amaksr/nsynjs/tree/master/examples
You need to use promise, in your controller, you should inject $q which will handle promise.
angularApp.controller('YourController', ['$q', '$scope',
function ($q, $scope) {
$scope.firstFunction = function () {
var deferred = $q.defer();
//Do things you want here...
console.log(1);
deferred.resolve();
return deferred.promise;
};
$scope.secondFunction = function () {
var deferred = $q.defer();
//Do things you want here...
console.log(2);
deferred.resolve();
return deferred.promise;
};
$scope.firstFunction().then(function () {
$scope.secondFunction.then(function () {
console.log(3)
})
})
}]);
console logs in functions above will print out:
1
2
3

Asynchronous and Synchronous in javaScript

I have to use the SP.RequestExecutor.js library. The problem is I need to run the async function in sync behavior. After deep search I found await and async methods but they are not compatible with Internet Explorer(IE>9). How I can make convert the async functions to sync and be compatible on IE>9 and Chrome?
function executorRun() {
console.log('end2');
var executor = new SP.RequestExecutor('path');
var result=[];
executor.executeAsync({
url: 'URL',
method: "POST",
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
},
data: JSON.stringify(requestData),
success: function (data) {
console.log('end3')
console.log(data);//Debug statement
//Handle data and store in result
},
error: function (error) {
console.log(error);
}
});
return result;
}
async function test () {
console.log('end1');
const data = await executorRun();
console.log('end4');
}
test();
I need the output ass follows:
end1
end2
end3
end4.
The above code is running in chrome but on IE refuse the await and async.
In order for await to work, executorRun needs to return a Promise.
function executorRun() {
console.log('end2');
return new Promise(function (resolve, reject) {
var executor = new SP.RequestExecutor('path');
executor.executeAsync({
url: 'URL',
method: "POST",
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
},
data: JSON.stringify(requestData),
success: function (data) {
console.log('end3');
console.log(data);//Debug statement
//Handle data and store in result
resolve(data);
},
error: function (error) {
reject(error);
console.log(error);
}
});
});
}
async function test () {
console.log('end1');
const data = await executorRun();
console.log('end4');
}
test();
To use async/await in IE9, you coudl transpile your code with Babel.
You could also just use the Promise directly without the syntactic sugar of async/await:
function test () {
console.log('end1');
executorRun().then(function (data) {
console.log('end4');
});
}
test();
IE doesn't support Promises natively, but they can easily be pollyfilled with any of the many Promise libraries out there.
If you don't want to use Promises, you could always just modify excecutorRun to accept a callback:
function executorRun(callback) {
console.log('end2');
var executor = new SP.RequestExecutor('path');
executor.executeAsync({
url: 'URL',
method: "POST",
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
},
data: JSON.stringify(requestData),
success: function (data) {
console.log('end3');
console.log(data);//Debug statement
//Handle data and store in result
callback(data);
},
error: function (error) {
console.log(error);
}
});
}
function test () {
console.log('end1');
executorRun(function (data) {
console.log('end4');
console.log(data);
});
}
test();

AngularJS http return value

I want to write a function in AngularJS that returns a value (actually it is a string). That value is returned by a http request, but async is driving me crazy.
My first attempt was:
this.readParameter = function(key) {
$http({
method: "GET",
url: "XXXXXXX",
headers: { 'Content-Type': 'application/json' }
}).then(function successCallback(response) {
return response.data;
}, function errorCallback(response) {
throw new Error("Error");
})
};
But of course it does not work because of Angular async features (response.data is undefined)
What is the way to do it? I just want to return the value (string), so I can use this function like
var a = readParameter("key1")
What you can do is define some variable with initial value outside function and on response set value inside success function instead of returning it.
Delegator pattern works great here to assign $http task to some service and use callback method for response.
Controller (Call Service for specific request) -> Service (Manage request params and other things and return factory response to Controller) -> Factory (Send request and return it to Service)
Basic example of Callback
var myVariable = '';
function myFunction (key, callback) {
$http({
method: "GET",
url: "XXXXXXX",
headers: { 'Content-Type': 'application/json' }
}).then(function successCallback(response) {
callback(response);
}, function errorCallback(response) {
throw new Error("Error");
})
};
function myCallbackFunction(response) {
myVariable = response.data; // assign value to variable
// Do some work after getting response
}
myFunction('MY_KEY', myCallbackFunction);
This is basic example to set value but instead use callback pattern from above example.
var myvariable = '';
function myFunction (key) {
$http({
method: "GET",
url: "XXXXXXX",
headers: { 'Content-Type': 'application/json' }
}).then(function successCallback(response) {
myvariable = response.data; // set data to myvariable
// Do something else on success response
}, function errorCallback(response) {
throw new Error("Error");
})
};
myFunction('MY_KEY');
Don't try to mix async and sync programming. Instead use a callback to use like
readParameter("key1", callback)
for example:
this.readParameter = function(key, callback) {
$http({
method: "GET",
url: "XXXXXXX",
headers: { 'Content-Type': 'application/json' }
}).then(function successCallback(response) {
callback(response)
}, function errorCallback(response) {
throw new Error("Error");
})
};
I resolve this by using promise:
Example :
in Service (invoicesAPIservice => invoicesapiservice.js) you use:
angular.module('app')
.service('invoicesAPIservice', function ($http) {
this.connectToAPI= function () {
return new Promise(function(resolve,reject){
var options = {
method:'GET',
url :'',
headers:{
'X-User-Agent': '....',
'Authorization': '....',
}
};
$http(options).then(function successCallback(response) {
resolve(response);
//console.log(response);
},function errorCallback(response) {
reject(response);
})
});
});
});
and in your Controller (mainCtrl=> mainCtrl.js):
angular.module('app').controller('mainCtrl', function($scope,invoicesAPIservice) {
$scope.connectToAPI=function () {
invoicesAPIservice.connectToAPI().then(function (content) {
console.log(content.statusText);
}.catch(function (err) {
//console.log(err);
alert("Server is Out");
});
}
});
And in your page : index.html:
<button ng-click="connectToAPI()"></button>
:)

Categories