I have the following Ajax call:
for (var i=0;i<localStorage.length;i++){
stored = localStorage.getItem(i.toString());
id=stored.split(':');
if ( id[0].toString()=="legislator" ){
bioguide_id=id[1];
$http({
method: 'GET',
url: 'getData.php',
params: {fav_legislator_value: bioguide_id}
}).then(function (response) {
fav_legislators.push(response.data.results[0]);})
}
}
I need all the Ajax call to complete and all results pushed to the array after that only I can start processing again. I have tried many ways by making this a function but nothing works. My whole script gets executed then the values are pushed to the array which is of no use to me. How to wait until all the calls are completed and the array is completely populated.
Store all the promises object into an array, and use $q.all to combine all promises into a single promise which will be resolved only if all of them have been resolved.
E.g.
var promises = [];
for (var i=0;i<localStorage.length;i++){
stored = localStorage.getItem(i.toString());
id=stored.split(':');
if ( id[0].toString()=="legislator" ){
bioguide_id=id[1];
var req = $http({
method: 'GET',
url: 'getData.php',
params: {fav_legislator_value: bioguide_id}
}).then(function (response) {
fav_legislators.push(response.data.results[0]);
});
promises.push(req);
}
}
$q.all(promises).then(function () {
// All result is now in `fav_legislators`.
})
Related
I have an array that can hold an unknown amount of indexes in it. Each index is used to send data with an ajax call. I am looping through with a for loop gathering the data from the successful call and pushing it into an empty array. At the end of the unknown amount of calls I then need to use that newly gathered array in my view. newDataArray is executed at the bottom before the loops are done and therefor it is still empty. How do I finish all the calls then do what is at the bottom?
If it helps, I am doing this in React with the Flux pattern. But the same issue may be done not in React. Here is a mock sample of what I am trying to do:
JS
case 'execute-calls':
//This is the new array to push to
var newDataArray = [];
//Url to call
var url = 'http://dev.markitondemand.com/Api/v2/Quote/jsonp';
for(let i = 0; i < payload.data.length; i++){
//given array of data that needs to be sent with call
let symb = { symbol: payload.data[i]};
$.ajax({
data: symb,
url: url,
dataType: "jsonp",
})
.done(function(data){
let updatedData = {
//...data that is stored from response
};
newDataArray.push(updatedData);
})
.fail(function(error){
//console.log(error);
});
}
//This will be updating the state object which is above the switch cases
//However this is ran before the end of the loops so newDataArray is empty
var updateTicker = {
updatedTicker: true,
updatedTickerSymbols: newDataArray
};
assign(stockData,updateTicker);
getStockData.emitChange();
break;
You can make use of the fact that $.ajax() actually returns a deferred object, and use it to create an array of deferreds. e.g.
var symbols = [1, 2, 3, 4];
var deferreds = symbols.map(function (symbol) {
return $.ajax({
url: 'http://dev.markitondemand.com/MODApis/Api/v2/Quote/jsonp',
data: { symbol: symbol },
dataType: 'jsonp'
});
});
You can resolve multiple deferreds at once with $.when(). There is a complication however, $.when() expects a list of parameters rather than array. We can solve this by using Function#apply.
To add to the complication, the callback function is also called with a list of arguments. Since we don't know how many arguments there are, we'll use the arguments pseudo-array. And since arguments isn't an actual array, we'll loop through it by using Function#call on Array#prototype.
$.when.apply($, deferreds).done(function () {
Array.prototype.forEach.call(arguments, function (response) {
console.log(response[0].Message);
});
}).fail(function (jqXHR, textStatus, error) {
console.error(error);
});
[UPDATED to include fail() call]
If you're using ES6 this is much more elegant:
$.when(...deferreds).done((...responses) => {
responses.forEach((response) => {
console.log(response[0].Message);
});
});
When ever you are dealing with ajax calls and have to do some operations at the end of all async calls then better choice would be to use Callback functions.
Modifying your code to use the call back,
function AsyncLoopHandler(index) {
if (index > payload.data.length) {
// all the indexes have finished ajax calls do your next step here
var updateTicker = {
updatedTicker: true,
updatedTickerSymbols: newDataArray
};
assign(stockData, updateTicker);
getStockData.emitChange();
}
else {
//given array of data that needs to be sent with call
let symb = { symbol: payload.data[index] };
$.ajax({
data: symb,
url: url,
dataType: "jsonp",
})
.done(function (data) {
let updatedData = {
//...data that is stored from response
};
newDataArray.push(updatedData);
AsyncLoopHandler(index++); // call the function again with new index
})
.fail(function (error) {
//console.log(error);
});
}
}
Now for starting this recursive function just start it by passing the index 0.
AsyncLoopHandler(0);
So all the ajax calls will be executed one after the other as if its an synchronous requests, And the if check will see if all the indexes are complete and then run your logic. Let me know if this helps
suggest use promise, logic would like
var urls= [x,x,x,x];
var results = [];
var qs = $.map(urls,function(url){
return function(){
var deferred = Q.defer();
$.ajax({
success:function(){
results.push(url)
deferred.reslove();
},error:function(){
deferred.reslove();
}
})
return deferred;
}
})
Q.all(qs).then(function(){
console.log(results )
});
or use yield and co in new standard
https://github.com/kriskowal/q
I have an array that I'm passing to a payload that will be posted to an API. In the array are field names that the API will take individually( not as an array) so I created a for loop to iterate thru the array and add the field names to the payload dynamically. But when I make the call, I get data for only the last field name. If I have say a total of 6 items in the array, I get data for just the last field.
function getData(payload, index, field) {
var deferred = $q.defer();
for (var i = 0; i < field.length; i++) {
if (field[i]) {
console.log("terms logged", field[i]);
var termsData = {
user_selection: payload,
index_info: index,
field: field[i]
};
console.log("terms data", termsData);
}
}
$http({
url: 'API',
method: "POST",
data: $.param(termsData),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).then(function (response) {
var data = response.data;
console.log("response data", data);
deferred.resolve(data);
});
return deferred.promise;
}
Do I need to repeat the loop after the initial call? Since it's in a for loop, I assumed the calls would be made one after another until the condition is met.
There are a couple of errors here. First, the return deferred.promise; will break out of the function the first time it is reached. So that's why it's only sending the first term. If you move the return statement outside of the for loop you should get all the terms sent.
What also should be fixed is you have only 1 deferred object attached to multiple calls. There should be a deferred object for each call. Below is an example.
function getData(payload, index, field) {
for (var i = 0; i < field.length; i++) {
if (field[i]) {
console.log("terms logged", field[i]);
var termsData = {
user_selection: payload,
index_info: index,
field: field[i]
};
postTerm(term);
}
}
}
function postTerm(term) {
var deferred = $q.defer();
console.log("terms data", term);
$http({
url: 'API',
method: "POST",
data: $.param(term),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function(response) {
var data = response.data;
console.log("response data", data);
deferred.resolve(data);
});
return deferred.promise;
}
I believe what you are looking for is a way to chain promises within a loop. This can be achieved storing the promises inside an array as this:
var promises = [];
for(...) {
var promise = $http(...); // http calls return a promise
promises.push(promise);
// Or, if you prefer to use $q
var deferred = $q.defer();
$http(...).success(function(){
deferred.resolve();
});
promises.push(deferred);
}
$q.all(promises).then(function(){
// This will be executed when all promises inside the array have been resolved
});
Although, I do not recommend doing so many requests. If possible, change your backend, enabling it to receive an array of objects alternatively.
Here some documentation about $q https://docs.angularjs.org/api/ng/service/$q
Resolve a promise array with Angular UI Router
My question is relatively straight forward.
I have an array of deferreds waiting to be returned, the code is like this:
var deferreds = [];
for(var i = 0; i < 5; i==){
deferreds.push(getOneResult(params));
}
var deferreds = [];
for(var i = 0; i < 5; i==){
deferreds.push(getOneResult(params));
}
The "getOneResult" function looks like this:
function getOneResult(params){
return $.ajax({
url: myURL,
data: params
});
}
It worked fine until one day I decided to let the "getOneResult" function to execute another ajax process and then using the result from this ajax process to get the result, so now my problematic code looks like this:
function getOneResult(params){
$.ajax({
url: myOtherURL,
data: params,
success: function(){
var result = arguments;
return $.ajax({
url: myURL,
data: arguments
});
}
});
}
Then all of a sudden all the items in "deferreds" array become "undefined". I am sure what I am doing sounds not right but is there anyway for me to run an ajax process before returning the deferred?
try returning the second promise. The original promise will now use the wrapped, second ajax promise.
function getOneResult(params){
return $.ajax({
url: myOtherURL,
data: params
}).then(function() {
return $.ajax({
url: myURL,
data: arguments
});
});
}
How do I fetch data from an array of json urls and store their contents in an array
<script type="text/javascript">
urls = ["https://spreadsheets.google.com/feeds/list/1RsiDuydBBHyu4OBjlxq1YH6yT3qcJDMB6-YKU-xxd_k/od6/public/basic?hl=en_US&alt=json","https://spreadsheets.google.com/feeds/list/1Pk4KnjBtYsIJF65ZQFEdBLqPufPK-HSFqhZvmxjZD_E/od6/public/basic?hl=en_US&alt=json"];
local = {};
$.ajax({
url: urls,
cache: false,
context: local,
dataType: 'jsonp',
success: function(data){
console.log(data);
}
});
</script>
The console.log method does not return any data and it does not return an error. How do I obtain data from the 2 urls I've used
No.
The array will be converted to a string, which won't be any of the URLs that you want, so you'll usually end up with a 404 error (which you won't see because you don't have an error handler (and I think there might be issues with detecting errors on JSONP requests anyway)).
If you want to loop over an array of URLs and make an Ajax request for each one, then you'll have to write the loop yourself, and call $.ajax each time you go around it.
You might want to consider using an iterator that you bump in the success function rather than using a simple for loop so that you don't attempt to fire off lots of requests in parallel.
jQuery doesn't have an overload for this by default, but you can achieve the same thing using promises and performing one AJAX request for each URL in the array:
var urls = ["https://spreadsheets.google.com/feeds/list/1RsiDuydBBHyu4OBjlxq1YH6yT3qcJDMB6-YKU-xxd_k/od6/public/basic?hl=en_US&alt=json","https://spreadsheets.google.com/feeds/list/1Pk4KnjBtYsIJF65ZQFEdBLqPufPK-HSFqhZvmxjZD_E/od6/public/basic?hl=en_US&alt=json"];
var $deferredArray = $.map(urls, function(url) {
console.log("here");
return $.ajax({
url: url,
cache: false,
success: function(data){
console.log("Success");
}
});
});
$.when.apply($, $deferredArray).then(function() {
console.log('All done');
});
You can use $.when.apply* for this. It allows you to pass in an array of promises and run a function when they have both completed. So something like this:
var urlArray = [url, url2];
var promises = [];
function returnPromise(url) {
return $.ajax({
url: url,
cache: false,
context: local,
dataType: 'jsonp'
});
}
// push each promise into your promises array
for (var i = 0, l = urlArray; i < l; i++) {
promises.push(returnPromise(urlArray[i]));
}
// pass the promises array into $.when
$.when.apply(null, promises).then(function (data1, data2) {
// do something with the data
});
*apply is available on every JS function and allows you to call it with an array of arguments instead of a list.
I am trying to wait for an ajax call to finish saving a model before saving the next model in the list. I was googling around and saw some stuff about deferred objects which are new to me, and another answer that had a recursive function do it. I tried the recursive method because it seemed to make a little more sense than with deferred objects and using $.when.apply($, arrayOfAjaxCalls).then(). So that code (the recursive one, looks like:
saveModel(index, numRequests) {
var self = this;
if (index < numRequests) {
var sample = self.samplesToSave[index];
return $.ajax({
url: model.url,
contentType: "application/json",
type: "POST",
data: JSON.stringify(model),
crossDomain: $.support.cors,
xhrFields: {
withCredentials: $.support.cors,
},
success: function(data) {
console.log("JUST SAVED");
console.log(data);
},
error: function(xhr: any) {
console.log(xhr);
},
}).then(() => {
self.saveModel(index + 1, numRequests);
});
}
}
I call this like:
saveModel(0, _.size(myCollection)
It doesn't actually wait for the ajax call to finish in its current state before calling the next saveModel. It basically just synchronously calls saveModel for each item in the collection in order. Any thoughts on what I'm missing? If there's a better solution with $.Deferred, I'm ok with that as well. Thanks.
Edit: Sorry it meant to say saveModel in the last line of the saveModel function. Was trying to get rid of parts that were domain specific. And I'm using typescript, not coffeescript
New attempt:
saveSampleNew() {
var d = $.Deferred();
d.resolve();
var p = d.promise();
var self = this;
self.samplesToSave.forEach(sample => p = p.then(() => self.makeSaveRequest(sample)));
return p;
}
makeSaveRequest(sample) {
var self = this;
return $.ajax({
url: "samples",
contentType: "application/json",
type: "POST",
data: JSON.stringify(sample),
crossDomain: $.support.cors,
xhrFields: {
withCredentials: $.support.cors,
},
success: function(data) {
console.log("SAVED12");
console.log(data);
},
});
}
Because this code depends on other async calls from completing, I call this new attempt like this:
this.saveContainers(project).then(() => {
}).done(() => {
self.saveSampleNew();
});
No, it should work this way. If you think it doesn't wait, please provide more information on how you call it and how experience that it does synchronously recurse.
There is one catch however with the recursive call:
.then(function() {
self.saveModel(index + 1, numRequests);
})
The promise that is returned by then, and subsequently by your saveModel method, does resolve directly with the first ajax call, it does not wait for the recursive chain. The other ajax calls are still happening (sequentially, as expected), but are not being tracked by the resulting promise.
To get that, and properly chain the promises so that it resolves with the result of the last ("innermost") promise, you will need to return the promise from the callback to then:
.then(function() {
return self.saveModel(index + 1, numRequests);
})
I'd probably use a for loop rather than a recursive call here, generally - I find those easier to read in this context.
saveModel() {
var d = $.Deferred(); d.resolve();
var p = d.promise(); // to start the chain
this.samplesToSave.forEach(sample => p = p.then(() => makeSaveRequest(sample));
return p;
}
makeSaveRequest(sample) {
return $.ajax({...}); // make request using `sample` as data
}