How can i handle multiple httpRequests using url strings from an array? Below is what I've tried so far but i receive an error each time I attempt to deploy the code to parse.
Parse.Cloud.define("FetchData", function(request, response) {
Parse.Cloud.useMasterKey();
var urls = ["url1", "url2"]
return Parse.Cloud.httpRequest({
//For loop below FAILS**
for (i = 1; i < 8; i++) {
url: urls[i]
},
}).then(function(httpResponse) {
//Handle Json here
response.success("Success");
},
function (error) {
response.error("Error: " + error.code + " " + error.message);
});
});
Cloud.httpRequest returns a promise to make the request. Call it in a loop, collecting those promises, then create a new promise using Promise.when() which is fulfilled when all of the http request promises are fulfilled:
var _ = require("underscore"); //so we can map over an array
var urls = ["url1", "url2", "url3"];
Parse.Cloud.define("FetchData", function(request, response) {
var promises = _.map(urls, function(url) {
return Parse.Cloud.httpRequest({ url:url });
});
Parse.Promise.when(promises).then(function() {
response.success(_.toArray(arguments));
}, function (error) {
response.error("Error: " + error.code + " " + error.message);
});
});
Related
I have this function
function actInfo(fund) {
var acct = $('.account');
$.ajax({
url: "account.php",
type: 'get',
dataType: 'json',
data: {fund: fund}
}).done(function (response) {
var len = response.length;
acct.empty();
for (var i = 0; i < len; i++) {
var acctNum = response[i]['ID'];
var acctName = response[i]['NAME'];
acct.append("<option value='" + acctNum + "'>" + acctNum + ' -- ' + acctName + "</option>");
}
acct.prepend("<option value=''>- Select An Account -</option>").val('');
}).fail(function (jqXHR, textStatus, error) {
console.log("actInfo: " + error);
});
}
I call this function in another ajax call because I need to send the function variable that I get from the server. In the same ajax call that I use to call actInfo(fund) I am also trying to select a value. Here is the main ajax call.
function getPoInfo(trnum) {
$.ajax({
url: "edit.php",
data: {trnum: trnum},
type: "GET",
cache: false,
dataType: "json"
}).done(function (poInfo) {
$('#fund').val(poInfo[0]['TRANFUND']);
actInfo(poInfo[0]['TRANFUND']);
$('#account1').val(poInfo[0]['TRANACCOUNT'].trim());
}).fail(function (jqXHR, textStatus, error) {
console.log("getPoInfo(tran_num): " + error);
});
}
The actInfo(fund) function works fine. It builds my dropdown menu. But I don't know how to select a value. I am assuming I am trying to select a value before the dropdown is loading. I don't understand callbacks or promises, and I tried .bind and tried to append .done and .load but I can't get a value selected. How do I do tell when the dropdown menu is finished loading and then select a value?
Since actInfo() method contains an asynchronous operation (basically the <select> element is only built after you have received and parsed the returned JSON response). Therefore, what you want is to:
create a new deferred object, i.e. var deferred = new $.Deferred()
return its immutable promise at the end, i.e. return deferred.promise().
The new deferred object should be resolved (deferred.resolve()) or rejected (deferred.reject()) based on the outcome of the inner AJAX request.
If we take all these points into account, your code can be easily be refactored as follow (I have added comments where I have added the suggested changes):
function actInfo(fund) {
var acct = $('.account');
// Create new deferred object
var deferred = new $.Deferred();
// Perform AJAX call as usual
$.ajax({
// Truncated for brevity
// ...
}).done(function (response) {
var len = response.length;
acct.empty();
for (var i = 0; i < len; i++) {
var acctNum = response[i]['ID'];
var acctName = response[i]['NAME'];
acct.append("<option value='" + acctNum + "'>" + acctNum + ' -- ' + acctName + "</option>");
}
acct.prepend("<option value=''>- Select An Account -</option>").val('');
// Now that the DOM has been built, we can resolve the promise and return it!
deferred.resolve();
}).fail(function (jqXHR, textStatus, error) {
console.log("actInfo: " + error);
// If we encounter an error, we pass it on!
deferred.reject(error);
});
// Return immutable promise
return deferred.promise();
}
Then, in your getPoInfo() method, simply check for the resolution of the returned promise from actInfo():
function getPoInfo(trnum) {
$.ajax({
// Truncated for brevity
// ...
}).done(function (poInfo) {
$('#fund').val(poInfo[0]['TRANFUND']);
// actInfo returns a promise!
var actInfoPromise = actInfo(poInfo[0]['TRANFUND']);
// Wait for the promise to resolve using $.when
$.when(actInfoPromise)
.then(function() {
// If successful, we select the correct <option>
$('#account1').val(poInfo[0]['TRANACCOUNT'].trim());
}, function(error) {
// If failed, we log the error message that has been passed on
console.log(error);
});
}).fail(function (jqXHR, textStatus, error) {
console.log("getPoInfo(tran_num): " + error);
});
}
I currently have a function which makes a httpRequest and parses the json received into an array of urls. I want to fire a second httpRequest after the first request is complete and data is parse, below both solutions I've tried return null.
Solution1
var promises1 = [];
Parse.Cloud.define("FetchData", function(request, response) {
var promises = _.map(urls, function(url) {
return Parse.Cloud.httpRequest({ url:url });
});
Parse.Promise.when(promises).then(function() {
createSearchUrls(arguments)
//Creates an array of urls from request data to be used in second http request
});
//Fire second HTTP request here after urls have been created from first request data
var promises1 = _.map(appTitles, function(appTitles) {
return Parse.Cloud.httpRequest({ url: appTitles});
});
Parse.Promise.when(promises1).then(function() {
//nothing returned
response.success(_.toArray(arguments));
}, function (error) {
response.error("Error: " + error.code + " " + error.message);
});
});
Solution 2 (Using then after createSearchUrl() function
Parse.Cloud.define("FetchData1", function(request, response) {
var promises = _.map(urls, function(url) {
return Parse.Cloud.httpRequest({ url:url });
});
Parse.Promise.when(promises).then(function() {
//Creates an array of urls from request data to be used in second http request
createSearchUrls(arguments).then( function() {
//Fire second HTTP request here after urls have been created from first request data
promises_1 = _.map(appTitles, function(appTitles) {
return Parse.Cloud.httpRequest({ url: appTitles});
});
})
});
Parse.Promise.when(promises_1).then(function() {
//nothing returned
response.success(_.toArray(arguments));
}, function (error) {
response.error("Error: " + error.code + " " + error.message);
});
});
createSearchUrls()
function createSearchUrls(arguments){
for (a = 0; a < arguments.length; a++){
var json = JSON.parse(arguments[a].text);
for (i = 0; i < json.feed.entry.length; i++) {
var urlEncoded = encodeURI(ENCODE JSON DATA);
var finalUrl = 'URL HERE';
appTitles.push(finalUrl);
}
}
return appTitles;
}
It looks like the idea of making a series of httpRequests and collecting the results is something that can and should be factored out....
function manyRequests(urls) {
var promises = _.map(urls, function(url) {
return Parse.Cloud.httpRequest({ url:url });
});
return Parse.Promise.when(promises).then(function() {
return _.toArray(arguments);
});
}
Now its just a matter of calling that twice....
Parse.Cloud.define("FetchData1", function(request, response) {
manyRequests(urls).then(function(results) {
createSearchUrls(results); // assigns to the gobal "appTitles"
return manyRequests(appTitles);
}).then(function(result) {
response.success(result);
}, function(error) {
response.error(error);
});
});
What that says is, call (a globally defined, presumably) list of urls and collect the results. From those results, run a local function to generate another list of urls (assigning those to a global, presumably), call those and return the result to the client.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I am making a project in MEAN Stack. In Frontend I have to do two things. First get data from backend using a promise. and use that data again in another promise. basically something like this.
var deviceId="";
deviceId = $http.get(Config.apiurl+'/mobile/devices')
.then(function(response){
deviceId = response.data.devices[0].deviceId;
console.log(deviceId);
return response.data;
}, function(response){
console.log("Error");
return $q.reject(response.data);
});
console.log(deviceId);
var postString = "AT+CGPSINF=0 0," + lat + "," + lng + ",847.413452,20150520205855.000,100,11," + velocity + ",0.000000 OK ,CRASH=0,"+deviceId;
$http.post(Config.apiurl + '/device/locations', postString, { headers: { 'Content-Type': undefined}})
.then(function (response) {
console.log("Sent the data");
return response.data;
}, function (response) {
console.log("got error response");
return $q.reject(response.data);
});
Now there is a conceptual problem that I need deviceId for my second API call and I won't get it synchronously, because promises are inherently asynchronous in nature. If I have to implement such a behavior. How do I go about it?
Second Ques. Whatever data I get inside my promises I am not able to get the same value outside the promise. That being said. I know that this must be caused because deviceId = response.data is a reference. So when response's scope ends.Value from deviceId is vanished. How do I get the data from the promises? or should I call the other promise inside the first one to make it synchronous and ensure that I always have the data?
Something like this should work
$http.get(Config.apiurl+'/mobile/devices')
.then(function(response) {
deviceId = response.data.devices[0].deviceId;
var postString = "AT+CGPSINF=0 0," + lat + "," + lng + ",847.413452,20150520205855.000,100,11," + velocity + ",0.000000 OK ,CRASH=0,"+deviceId;
return $http.post(Config.apiurl + '/device/locations', postString, { headers: { 'Content-Type': undefined}});
}).then(function (response) {
console.log("Sent the data");
return response.data;
}).catch(function(err) {
console.log('got an error');
console.log(err);
});
Look this:
function getMobileDevices(callback){
$http.get(Config.apiurl+'/mobile/devices').then(function(response){
callback(response);
}, function(response){
console.log("Error");
return $q.reject(response.data);
});
}
function getLocationDevices(callback, deviceId){
var postString = "AT+CGPSINF=0 0," + lat + "," + lng + ",847.413452,20150520205855.000,100,11," + velocity + ",0.000000 OK ,CRASH=0,"+deviceId;
$http.post(Config.apiurl + '/device/locations', postString, { headers: { 'Content-Type': undefined}}).then(function (response) {
callback(response.data)
}, function (response) {
console.log("got error response");
return $q.reject(response.data);
});
};
function go(){
getMobileDevices(function(response){
var deviceId = response.data.devices[0].deviceId;
getLocationDevices(function(response){
console.log("Response: " + response)
}, deviceId);
});
}
Uses callback function when called search http. When finishing callback return the value of response
I was wondering what the order of operations are in the parse cloud. I currently am running into trouble trying to do multiple things at once inside my job on the cloud. I am currently trying to make an HTTP request for each user in my user table (there are 2) and then get the webpage or httprequest.text from the webpage. My code is as followed
Parse.Cloud.job("WeatherUpdates2", function(request, status) {
var query = new Parse.Query(Parse.User);
query.exists("City");
query.each(
function(result){
var object = result;
console.log(object.id);
var city = object.get("City");
city = city.replace(" ", "");
city = city.replace(" ", "");
// get the country code.
var countryCode = object.get("CountryCode");
var woeidUrl = "http://where.yahooapis.com/v1/places.q(" + city + "," + countryCode + ")?appid=(appid)";
console.log(woeidUrl);
var woeID = "An error occured retrieving your WOEID.";
Parse.Cloud.run('httpRequest', { url: woeidUrl }, {
success: function(WOEID) {
console.log("returned from http request.");
},
error: function(error) {
console.log("Error occurred while making request for WOEID " + error.message);
status.error(error.message);
}
});
},
{
success: function() {
// results is an array of Parse.Object.
console.log('#Query');
status.success("Updated Records!!");
},
error: function(error) {
// error is an instance of Parse.Error.
console.log('#error');
response.error("Failed to save vote. Error=" + error.message);
}
});
});
Where the job httpRequest is:
Parse.Cloud.define("httpRequest", function(request, response) {
var webpage = "Something went wrong.";
Parse.Cloud.httpRequest({
url: request.params.url,
success: function (httpResponse) {
webpage = httpResponse.text;
webpage = webpage.toString();
response.success(webpage);
},
error: function (error)
{
console.log("Error in http request " + error.message);
response.error(error.message);
}
});
});
now I would expect to be printed would be the, object id of first user, their url, the job running, the message"returned from http request." then repeated another time for the second user and finally the job finishing with the message "Updated Records". but instead I get:
I2014-07-22T15:15:16.013Z] A5hod7qKE3
I2014-07-22T15:15:16.045Z] http:/where.yahooapis.com/v1/places.q(Draper,US)?appid=(appid)
I2014-07-22T15:15:16.053Z] GmuqxpTUpM
I2014-07-22T15:15:16.066Z] http:/where.yahooapis.com/v1/places.q(SaltLakeCity,US)?appid=(appid)
I2014-07-22T15:15:16.082Z] #Query
I2014-07-22T15:15:16.131Z] v385: Ran cloud function httpRequest with:
Input: {"url":"http://where.yahooapis.com/v1/places.q(SaltLakeCity,US)?appid=(appid)"}
Result:
2487610TownSalt Lake CityUnited StatesUtahSalt LakeSalt Lake City40.777561-111.93071740.699890-112.10125740.852951-111.739479511America/Denver
I2014-07-22T15:15:16.141Z] v385: Ran cloud function httpRequest with:
Input: {"url":"'http://where.yahooapis.com/v1/places.q(Draper,US)?appid=(appid)'"}
Result:
http://where.yahooapis.com/v1/schema.rng'" xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:start="0" yahoo:count="1" yahoo:total="11">2393601TownDraperUnited StatesUtahDraper8402040.524139-111.86627240.442921-111.92212740.544361-111.78304349America/Denver
I removed 1 / from both the printing urls so I could posts this because I don't have high enough rep to post more than 2 links. I also have put in my appid into the (appid) so the url does return to me the according woeid from yahoo.com. The problem here being I can't actually get into the success function of the http request job. Any help is greatly appreciated!
EDIT:
I was trying to figure out how to run a job in a for loop but couldn't get it to work. I tried to make a promise and do what Fosco said below, but have had no luck. Here is my code.
for(var i = 0; i < woeIDs.length; i++)
{
console.log("hello");
var weatherURL = "http://weather.yahooapis.com/forecastrss?w=" + woeIDs[i] + "&u=f";
var promise = Parse.Cloud.run('httpRequest', { url: weatherURL }, {
success: function(WOEID) {
console.log("got here");
},
error: function(error) {
console.log("Error occurred while making request for WOEID " + error.message);
status.error(error.message);
}
});
Parse.Promise.when([promise]).then(function() { status.success(); });
}
if I run this code I get a hello twice then the two job calls then the "got here" message once. I have tried adding a return statement to it and with no luck also. Thanks again for all the help!!!
The issue here is that inside the each callback, you need to return the promise from your cloud function call if you want to ensure the tasks complete, and have it wait before going to the next object.
Simplified and using promises:
query.each(function(object) {
...
return Parse.Cloud.run(...);
}).then(function() {
// success
}, function(err) {
// error
});
For looping over a promise-returning function like Parse.Cloud.run:
var promises = [];
for (i = 0; i < 5; i++) {
promises.push(Parse.Cloud.run('...', {}));
}
Parse.Promise.when(promises).then(function() {
// all done
}, function(err) {
// error
});
I am writing a simple app where I need to get the data from a http get api call and store it in Parse for some reason not all the data is stored. Also the http call returns before saving all the data here is the code.
How can I make it to return only after saving all the data?
Parse.Cloud.httpRequest({
url: 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/upcoming.json?apikey=apikey',
success: function(httpResponse) {
var jsonobj = JSON.parse(httpResponse.text);
var total = jsonobj.movies.length;
for ( var idx in jsonobj.movies) {
var movie = new Movie();
movie.save(new Movie(jsonobj.movies[idx])).then(
function(object){
console.log(object)
},
function(error){
console.log(error);
}
)
}
response.send("All saved");
},
error: function(httpResponse) {
console.error('Request failed with response code ' + httpResponse.status);
response.send("Failed");
}
})
You need to aggregate all the promises you used via an aggregation function, in the case of parse promises, it's .when :
Parse.Cloud.httpRequest({
url: 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/upcoming.json?apikey=apikey',
success: function(httpResponse) {
var jsonobj = JSON.parse(httpResponse.text);
var total = jsonobj.movies.length;
var results = [];
// do NOT iterate arrays with `for... in loops`
for(var i = 0; i < jsonobj.movies.length; i++){
var movie = new Movie();
results.push(movie.save(new Movie(jsonobj.movies[i]))); // add to aggregate
}
// .when waits for all promises
Parse.Promise.when(promises).then(function(data){
response.send("All saved");
});
},
error: function(httpResponse) {
console.error('Request failed with response code ' + httpResponse.status);
response.send("Failed");
}
})
Although, it might be better to use promises for the httpRequest too, this should work.