I want to make an Ajax call for every item in an array, and when all the calls have returned, I want to call another function.
To make things a little more complicated, I'm using Papa Parse to make the Ajax call.
This is my code:
getCsvData: function(url) {
var _this = thisl
Papa.parse(url, {
download: true,
complete: function(data) {
return data;
}
});
},
getBackendData: function() {
var _this = this;
var results = {};
_this.numeratorIds.forEach(function(d) {
var url = _this.constructUrl(d.id, d.query_type);
results[url] = _this.getCsvData(url);
});
// When everything is finished...
// call another function to render the data.
},
I'm not sure this is quite right - is there a better way of doing things?
NB: I realise it's slower to do multiple Ajax calls than to chain URL parameters and make a single call, but I think it's the right thing to do in my situation - I am working with a very large, very static database, and it will mean that I can cache these queries more often.
Why you are trying to do make multiple AJAX calls instead doing of that the controller return List of object that you want. Then you will not need to make multiple Ajax calls. What you will need is just one Ajax and you will have list of objects that you want and then you can bind that data onto your views.
Hope it make sense.
Related
I need to read two JSON URLs with jQuery, mangle them together and then proceed updating my UI from the JSON data.
With the two URLs in URLA and URLB and a global variable globalDataA I tried:
function useBothData(dataB) {
// use dataB and globalDataA
};
function useDataA (data) {
globalDataA = data
$.getJSON (URLB, useBothData);
};
$.getJSON (URLA, useDataA);
The idea is that after loading the 1st URL I load the 2nd and then work with them. However this does never seem to return. (I get the Brwoser warning "Script takes too long".)
How can I arrange jQuery's getJSON calls for the two URLs (and their success functions), so that I can then use their data in finally one function?
You can use the callback function of getJSON
$.getJSON(URLA, useDataA, function(dataB) {
//useBothData = globalDataA + dataB
$.getJSON(URLB, useBothData, function(result) {
//do more stuff
})
});
So I've got some code that retrieves a series of objects from an API. When I try to store them in a global variable, it doesn't seem to do anything. Here's the code:
var current_corpus = {};
function page_init() {
$.getJSON("http://resource1.com", function(data) {
populate_collections(data);
populate_citations(data);
});
}
function populate_collections(collections) {
$.each(collections, function (i, item) {
current_corpus[item] = [];
});
}
function populate_citations(collections) {
$.each(collections, function (index, collection) {
$.getJSON("http://resource2.com/" + collection.collection_id, function(data) {
current_corpus[collection] = data;
console.log(current_corpus);
});
});
}
When this finishes, current_corpus is completely empty. Logging these items verifies that they're being returned from the resources I'm posting to. I think there's just something about the asynchronous nature of these calls that I'm missing.
The line
current_corpus[item] = [];
is superfluous I think as the line
current_corpus[collection] = data;
should do the same thing while also tying data to the key object. Either way at the end of these functions running trying to access current_corpus via the console just gives me back an empty object.
Resources for dealing with AJAX stuff like this would be appreciated as well.
It all depends on what you want to do when the ajax requests complete. The A in ajax stands for Asynchronous meaning that such requests are non-blocking -- i.e. they will run in the background as control moves to the next line. Which explains why you're seeing an empty object right after the functions that invoke the ajax requests.
You can confirm that your code is working fine or you can do something once all the requests complete by using the following code snippet:
$(function() {
$(document).on('ajaxStop', function() {
console.log( current_corpus );
//do something with the now fully constructed object
});
});
So far I'm having no issue setting up an AngularJS model in my Rails application and giving it data to access on the front-end. I even set it up to be populated with data from an AJAX request using $http. However, I need this this model to contain the data of multiple $http calls. Here's the code I've got thus far:
function DropboxCtrl($scope, $http) {
var $infiniteLoader = $(".infiniteLoader");
var theUIDS = $infiniteLoader.attr('data-dropbox-uids').split(',');
if($infiniteLoader.attr('data-dropbox-uids') != "") {
var theData = {};
$.each(theUIDS, function(key) {
$http({ url: '/dropbox/files/get', method: 'GET', params: { uid: theUIDS[key] }}).success(function(data) {
theData = data;
});
});
$scope.dropboxes = theData;
}
}
I have a method called DropboxCtrl which will start by getting all the UID's that I need to call a GET request on. I loop through each of them and then append data to theData which is a Javascript object. After the each I make my dropboxes model equal to the value of theData. Current I've got the method returning absolutely nothing and no Javascript errors. I am positive that my url works completely and actually did get the code working with just one AJAX request like such:
$.each(theUIDS, function(key) {
$http({ url: '/dropbox/files/get', method: 'GET', params: { uid: theUIDS[key] }}).success(function(data) {
$scope.dropboxes = data;
});
});
However... that code block only returns the last AJAX call because the other ones are overwritten. Maybe what I'm missing is just incorrect Javascript, however, maybe what I'm missing is just a lack of understanding the "Angular way" of things. I'm skilled in Javascript and jQuery, but very new to Angular. Any help?
AngularJs is a high level Javascript framework. The code ultimately is javascript. Within your $each, you can push results to an array or to an initialized collection like
$scope.dropboxes = [{uid:1234}, {uid:2345}] and so on.
within the $each, locate the record for uid and attach the results.
I usually use underscorejs library for operations on collections, arrays etc.
so something like
_.findWhere($scope.dropboxes, {uid: data.uid }).data = data;
assuming the data that is returned has uid in it. If not then there should be another way to map the results to the request. Note that there is no guarantee of the order of responses, so you cannot use array indexes to map results.
I have a collection which has to call 4 external apis Eg: http://www.abc.com, http://www.fgt.com, http://www.jkl.com and http://www.rty.com.
I have a Collection named Todos.js. Is there a way I can fetch the 4 apis together in a single collection since all the four apis would provide me the same model response
So the response I get from the 4 apis has the same data structure i.e. "name" and "link".
Is there a way I can append all the responses in the same collection? What is the best way to achieve this?
I think the way is to override fetch, where you make the Ajax call to each of the APIs. Store the returned partial sets in a temporary array, and when all 4 are complete, create the collection using this.reset. (You could use JQuery's Deferred I suppose, or just keep an internal count of how many calls have returned.)
Something like this:
var Collection = Backbone.Collection.extend({
fetch: function() {
this.completeCount = 0;
this.errorCount = 0;
this.temp = [];
this.urls = [ 'url1', 'url2', 'url3', 'url4' ];
var self = this;
// make a $.get call for each URL and add
_.each(this.urls, function(url) {
$.get(url, { success: function(data) {
console.log("Got partial collection from " + url);
self.addPartial(data);
// alternatively, just call "self.add(data);" here
}, error: function(response) {
console.log("Oops, the Ajax call failed for some reason... ignoring");
self.completeCount ++;
self.errorCount ++;
} });
});
},
// add a JSON array that contains a subset of the collection
addPartial: function(data) {
this.completeCount ++;
var self = this;
// add each item to temp
_.each(data, function(item) {
self.temp.push(item);
});
// if all have been received, then create the collection
if (this.completeCount == this.urls.length) {
this.reset(this.temp);
}
}
});
Here's a Fiddle where I replaced $.get with a method that just returns dummy data after a short delay.
Response to comment
Adding the responses to the collection as they come in is probably better (it's easier anyway). Here's an updated Fiddle.
I know it's an old question, but if someone reaches in here this information may help.
To preserve the data previosly fetched by a collection, you can change the url and call the method fetch() any times needed with this options:
reset: false,
remove: false,
Like this
yourCollection.fetch({reset: false, remove: false, [other]: [wathever]})
And that's all, no need for overriding the method. (Maybe in 2012 it was necesary, dunno. The fact is that those options work for Backbone 1.1.2 or later). Be aware that im not sure if this will merge or just add the new data even if it's reppeated.
The documentation (http://backbonejs.org/#Collection-fetch) is a little confusing about the 'reset' option, because it says is settled false by default, perhaps that may only apply when the url remains static and single.
I'm writing some JavaScript/AJAX code.
Is there anyway to ensure that the server receives the XML requests in the order that they are sent?
If not with plain Ajax, do I get this guarantee if I send everything over a single WebSocket?
Thanks!
If it is of utmost importance that they're received in the proper order, and attaching an iterating id to the form isn't enough:
msg_number = 1; sendAJAX(msg_number); msg_number++;
Then I'd suggest building your own queue-system, and send each subsequent file as the callback of the previous one.
Rather than each element having its own AJAX-access, create one centralized spot in your application to handle that.
Your different AJAX-enabled sections don't even need to know that it is a queue:
AJAX.send({ url : "......", method : "post", success : func(){}, syncronous : true });
On the other side of that, you could have something like:
AJAX.send = function (obj) {
if (obj.synchronous) {
addToSyncQueue(obj); checkQueue();
} else { fireRequest(); }
};
Inside of your sync queue, all you'd need to do is wrap a new function around the old callback:
callback = (function (old_cb) {
return function (response) {
checkQueue();
old_cb(response);
};
}(obj.success));
obj.success = callback;
AJAX.call(obj);
Inside of checkQueue, you'd just need to see if it was empty, and if it wasn't, use
nextObj = queue.shift(); (if you're .push()-ing objects onto the queue -- so first-in, first-out, like you wanted).
A couple of options come to mind:
Send them synchronously, by waiting for a successful response from the server after each XML request is received (i.e. make a queue).
If you know the number of requests you'll be sending beforehand, send the request number as a tag with each request, e.g. <requestNum>1</requestNum><numRequests>5</numRequests>. This doesn't guarantee the order that they're received in, but guarantees that they can be put back in order afterwards, and has the added benefit of being sure that you have all the data.
At my company we use this little ajaxQueue plugin, written by one of the core jQuery contributors:
http://gnarf.net/2011/06/21/jquery-ajaxqueue/