TL;DR: I can get individual file progress bars and wait for them to finish before submitting the form but I have to send the files twice. How can I accomplish this with only sending the files once?
I wasn't even sure what to title this. This is my scenario:
I'm redoing our quote form on our company's website. We currently have a small section where a user can upload an RFP or some other projects as part of a quote request. Currently we are using Uploadify, but we have run into edge cases on OS X where it won't work in certain browsers. Plus, I plain don't like the markup it produces and it uses Flash (for the free version).
We're changing some behind the scenes functionality of the way quotes are sent and I asked my manager if I could get rid of the Uploadify implementation and use a native HTML5/JS solution instead. I let him know it would take some time since my knowledge on the matter was only cursory, but he agreed knowing we'd be using this more and more in the future.
So basically I have everything working but one small catch. The form redirects before all the progress bars finish. I'm not sure how to make the form "wait" for the bars/uploads to complete before it redirects (it redirects to a thank you page).
To play around with this on my own time I recreated a similar scenario at home with just a simple form with 3 fields and a drag/drop area for files. I have a nice animation and message on the button displaying while the files are uploading and the progress bars are going. Once it's finished, the button returns and I have an alert fire (no redirect while I am figuring this out on my own).
This is my form submission function which uses the $.ajax() function:
$('#submit').click(function(event)
{
event.preventDefault();
if(submitting)
{
return;
}
var formdata = new FormData($('#form')[0]);
for(var i = 0; i < the_files.length; i++)
{
formdata.append('file' + i, the_files[i]);
}
$.ajax(
{
url: 'http://' + path + ':9000/file/form.php',
type: 'POST',
data: formdata,
dataType: 'json',
async: true,
cache: false,
contentType: false,
processData: false,
beforeSend: function()
{
$('#submit').html('<span class="fa fa-refresh fa-spin"></span>' + 'Submitting...').prop('disabled', true);
for(var j = 0, file; j < the_files.length; j++)
{
i = the_files[j].index;
var onprogressupdate = function(i, event)
{
if(event.lengthComputable)
{
var percent = event.loaded / event.total * 100;
$('#file' + i + ' div.background').css('width', percent + '%');
}
};
var load = function(i, event)
{
$('#file' + i + ' div.inner span:first-child').text($('#file' + i + ' div.inner span').text() + ' - Complete!');
};
var filedata = new FormData();
var xhr = new XMLHttpRequest();
filedata.append('file', the_files[j]);
xhr.upload.addEventListener('progress', onprogressupdate.bind(null, i), false);
xhr.upload.addEventListener('load', load.bind(null, i, j), false);
xhr.open('post', 'http://' + path + ':9000/file/upload.php');
xhr.send(filedata);
}
},
success: function(response)
{
$('#submit').html('<span class="fa fa-upload"></span>' + 'Submit').prop('disabled', false);
submitting = false;
alert('debug');
}
});
});
Note the for loop just before the $.ajax() firing. I have to send the files twice to simulate the uploading finishing and then submitting the form (even though technically they are happening at the same time). Obviously this is not ideal; I don't want to have to send the files twice, though in my testing it does not seem to impact performance. I understand the beforeSend() function is asynchronous as well as AJAX itself.
I have tried sending the files with the formdata only and they do upload successfully but I am unaware of a way to then get individual progress updates with that method. I can only seem to get a progress update for the whole upload, which is not desired. My understanding is because there's only one XHR object in that instance.
All my reading (I have done a lot of online searching regarding this) on forcing things to be synchronous says it will lead to locking the user's browser, which of course is undesirable and I know if I were to implement something like that my manager would not be happy.
I get pretty close to what I wanted by tracking the last file that was finishing uploading and then checking its state and if it was 4 then execute a function that submits the form. This would kinda work but it would be obvious that the progress bar didn't fully complete before submitting and redirecting.
Any insight or help would be appreciated. Thanks!