Reputation: 839
I'm uploading a list of documents to the server, and for each document I launch an ajax request, but the number of requests is unknown (Depends on the number of document being uploaded). How can I show a message to the user when all the documents are uploaded (All ajax requests are done).
$.each(files,function(idx,elm){
let formData = new FormData();
let ID = '_' + Math.random().toString(36).substr(2, 9);
formData.append('document_id', ID);
formData.append('file-doc', elm);
$.ajax({
url: "http://127.0.0.1:5000/add_multiple_docs",
type: 'POST',
data: formData,
cache: false,
contentType: false,
processData: false,
beforeSend: function (xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
},
success: function (data) {
alert(data);
},
failure: function (request) {
console.log(request);
},
error: function (jqXHR, exception) {
console.log("error add document");
let msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status === 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status === 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
console.log(msg)
}
});
});
}
Upvotes: 0
Views: 509
Reputation: 1
A very interesting question.
I had a similar issue when trying to get data from the youtube API which only returned a max result set of 50 items.
To solve this problem I used a recursive function that accepted a callback, on base case (in my case when there was no nextPageToken) I called the callback function.
The recursion was triggered in the success handler of the $.ajax request.
function fetchVideos(nextPageToken, callback) {
if (nextPageToken === null || nextPageToken === undefined) {
callback(null);
return;
}
$.ajax(requestURI + `&pageToken=${nextPageToken}`, {
success: (data) => {
// use data somehow?
fetchVideos(data.nextPageToken, callback);
},
error: (err) => {
callback(err);
}
})
}
fetchVideos("", (err) => {
if (err) {
console.log(err.responseJSON);
return;
}
updateUI();
})
When there was no longer a nextPageToken in the response it would trigger the if statement. I think it works kind of sync? Because I need the nextPageToken to perform the next request.
I know this is not the best case for you situation, but I answered based on the title which is how I came to this page :)
Upvotes: 0
Reputation: 1616
First of all, you know how many files are uploaded, so you know how many ajax request you are doing. (1 Request per file)
So before your $.each()
fires you get the size of files
let count = $(files).size();
$.each(files,function(idx,elm){
/*your code with requests*/
}
Now, after each ajax request hast fired, decrement count
. Decrement inside your success
and failure
methods, because it doesn't mattet if it succeeded or not. And check if count === 0
. If it's 0 than you know all ajax are done.
$.ajax({
/*your other settings*/
success: function (data) {
alert(data);
count--;
doSomething(count);
},
failure: function (request) {
console.log(request);
count--;
doSomething(count);
},
});
function doSomething(count){
if(count === 0){
/*stuff you wannna do after all ajax requests are done*/
}
}
I haven't done that many ajax for now, so I'm not quite sure if failure
is also fired on error
, but if not maybe add count--
and the if on error as well.
Upvotes: 2
Reputation: 337560
To achieve what you need you can place all the jqXHR objects returned from $.ajax()
in an array which you can apply()
to $.when()
. Then you can execute whatever logic you require after all of those promises have been resolved. Try this:
var promises = files.map(function(elm) {
// setup formData...
return $.ajax({
url: "http://127.0.0.1:5000/add_multiple_docs",
// ajax settings...
});
});
$.when.apply($, promises).done(function() {
console.log('all requests complete, do something here...');
});
However, it's definitely worth noting that sending AJAX requests in a loop is not a scalable pattern to use. It would be a much better idea to aggregate all the file and related data in a single AJAX request and handle that once on the server.
Upvotes: 1