I'm using jQuery to upload a photo, and have attached a listener for onprogress events. However even when uploading photos that are a few megabytes, the only onprogress event that gets fired is when its at 100%. I've seen other sites like dropbox and facebook show a much more fluid progress bar. How can I get more frequent updates on the upload progress?
Sample upload Code:
var file = $photoFile.get(0).files[0];
var fileBlob = file && file.slice();
var formData = new FormData();
var title = $photoTitle.val();
formData.append('file', fileBlob);
formData.append('title', title);
$.ajax({
url: '/api/v1/photo/submit',
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'POST',
xhrFields: {
onprogress: function(ev) {
console.info('upload progress', ev);
if (ev.lengthComputable) {
var percentUploaded = Math.floor(ev.loaded * 100 / ev.total);
console.info('Uploaded '+percentUploaded+'%');
// update UI to reflect percentUploaded
} else {
console.info('Uploaded '+ev.loaded+' bytes');
// update UI to reflect bytes uploaded
}
}
}
}).done(function(response) {
// do stuff
}).fail(function() {
// handle error
});
I was able to do this borrowing code from this stackoverflow question.
The key mistake I was making was relying on the onprogress within the xhrFields property of the call to $.ajax. Instead, to get more frequent progress updates I passed a custom XMLHttpRequest using the xhr property:
$.ajax({
url: '/api/v1/photo/submit',
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'POST',
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
myXhr.upload.addEventListener('progress',function(ev) {
if (ev.lengthComputable) {
var percentUploaded = Math.floor(ev.loaded * 100 / ev.total);
console.info('Uploaded '+percentUploaded+'%');
// update UI to reflect percentUploaded
} else {
console.info('Uploaded '+ev.loaded+' bytes');
// update UI to reflect bytes uploaded
}
}, false);
}
return myXhr;
}
}).done(function(response) {
// do stuff
}).fail(function() {
// handle error
});
Warning: This leverages newer web technologies and doesn't work with older browsers, especially IE.
Related
I have an interesting problem - I have my own IIS 2016 server, that I use to host a website which allows the users to upload a variety of files - some in text format, the others zip'ed up together. Initially the website would return error 500 from the server when trying to upload something bigger, like ~50MB. I Googled up that IIS requires configuration of maxAllowedContentLength (changed default to 209715200, ~300MB) and FastCGI's parameters for IDLE, ACTIVITY and REQUEST (changed to 600) in order to allow bigger files upload without hitting the file size limit. However, now that the files are getting uploaded, the upload speed for these bigger files slowed down to a crawl. Previously I could upload ~20MB files in 10sec on a local network, while now 50MB takes like ~160sec. Not a linear increase I would expect.
My website runs on Django, and my POST method file transfer is carried out by Ajax call in JS:
$('#sn').on('submit', function(event) {
event.preventDefault();
var post_data = new FormData($("#sn")[0]);
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
var percent = Math.round(evt.loaded/evt.total * 100)
console.log(percent)
$('#query_button').attr('disabled', true)
$('#query_button').get(0).innerText = "Upload status: " + percent + '%'
}, false);
xhr.upload.addEventListener("load", function(evt) {
$('#query_button').get(0).innerText = "PLEASE WAIT..."
}, false);
return xhr;
},
url: '#',
type: "POST",
data: post_data,
processData: false,
contentType: false,
dataType: "json",
statusCode: {
200: function() {
// alert("Server received request and posted a response!");
},
404: function() {
alert("Error code 404: Page not found!");
},
408: function() {
alert("Error code 408: Request Timeout!");
},
500: function() {
alert("Error code 500: Internal server error!");
}
},
success: function(response) {
console.log(response)
}
});
})
Can anybody please tell me, if the Ajax call could be the culprit of this slow-down in upload speed, or if it is something else that needs to be adjusted on IIS?
Problem:
I have a situation where I'd like to upload a file (pdf, image, etc.) to an API Endpoint that accepts one of these types of files. However, the file is located on another web service somewhere. I'm trying to devise a clever solution that will allow me to (a) download the remote file (and store it as bytes in memory or something) then (b) upload that file through the API.
I have jQuery code that demonstrates how to upload a local file using jQuery with no backend code, but I'd like to extend it to allow me to upload something that is stored remotely.
Constraints:
I don't want to use any backend infrastructure on my image uploading page (ie. no php, python, ruby, etc.)
I don't want the end user of my form to need to download the file to their machine and upload the file as a two-step process.
What I've got so far:
I've seen some solutions on SO that kind-of connect the dots here in terms of downloading a file as a bytearray, but nothing that demonstrates how you might upload that.
Download File from Bytes in JavaScript
jQuery-only File Upload to Stripe API*
Keep in mind, Stripe is the example I have, but I'd like to try and replicate this on say Imgur or another API (if I can get this working). Hopefully someone else has some ideas!
$('#fileinfo').submit(function(event) {
event.preventDefault();
var data = new FormData();
var publishableKey = 'pk_test_***';
data.append('file', $('#file-box')[0].files[0]);
data.append('purpose', 'identity_document');
$.ajax({
url: 'https://uploads.stripe.com/v1/files',
data: data,
headers: {
'Authorization': 'Bearer ' + publishableKey,
// 'Stripe-Account': 'acct_STRIPE-ACCOUNT-ID'
},
cache: false,
contentType: false,
processData: false,
type: 'POST',
}).done(function(data) {
$('#label-results').text('Success!');
$('#upload-results').text(JSON.stringify(data, null, 3));
}).fail(function(response, type, message) {
$('#label-results').text('Failure: ' + type + ', ' + message);
$('#upload-results').text(JSON.stringify(response.responseJSON, null, 3));
});
return false;
});
I actually got this working for Stripe by doing this:
https://jsfiddle.net/andrewnelder/up59zght/
var publishableKey = "pk_test_xxx"; // Platform Publishable Key
var stripeAccount = "acct_xxx"; // Connected Account ID
$(document).ready(function () {
$('#file-upload').on('submit', function (e) {
e.preventDefault();
console.log('Clicked!');
var route = $('#file-route').val(); // URL OF FILE
var fname = route.split("/").slice(-1)[0].split("?")[0];
var blob = fetchBlob(route, fname, uploadBlob);
});
});
function fetchBlob(route, fname, uploadBlob) {
console.log('Fetching...')
var oReq = new XMLHttpRequest();
oReq.open("GET", route, true);
oReq.responseType = "blob";
oReq.onload = function(e) {
var blob = oReq.response;
console.log('Fetched!')
uploadBlob(fname, blob);
};
oReq.send();
}
function uploadBlob(fname, blob) {
var fd = new FormData();
fd.append('file', blob);
fd.append('purpose', 'identity_document');
console.log('Uploading...');
$.ajax({
url: 'https://uploads.stripe.com/v1/files',
data: fd,
headers: {
'Authorization': 'Bearer ' + publishableKey,
'Stripe-Account': stripeAccount
},
cache: false,
contentType: false,
processData: false,
type: 'POST',
}).done(function(data) {
console.log('Uploaded!')
}).fail(function(response, type, message) {
console.log(message);
});
}
The file upload function working on the Upload button click.The function
$("#fuPDFAdd").change(function () {})
file upload change is working two time when click the 'btnUploadAdd' button.
How can avoid this
<div id="divUploadFileAdd">
<form enctype="multipart/form-data" id="frmUplaodFileAdd">
#Html.AntiForgeryToken()
<input id="fuPDFAdd" name="file" type="file" style = "display:none;"/>
<button class="" id="btnUploadAdd" type="button" onclick="test()">Upload</button>
<label id="txtuploadedMsgAdd"> </label>
</form>
</div>
$(document).ready(function () {
$("#fuPDFAdd").change(function () {
console.log("tst1");
var file = this.files[0];
fileName = file.name;
size = file.size;
type = file.type;
if (type.toLowerCase() == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { //I just want pdf files and only want to show
var formData = new FormData($('#frmUplaodFileAdd')[0]);
$.ajax({
url: "UploadFile", //Server script to process data
type: 'POST',
async: false,
xhr: function () { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) { // Check if upload property exists
myXhr.upload.addEventListener('progress',
progressHandlingFunction, false); // For handling the progress of the upload
}
return myXhr;
},
data: formData,
//Options to tell jQuery not to process data or worry about content-type.
cache: false,
contentType: false,
processData: false,
success: function (data) {
grdStaffAddition.PerformCallback({ transStatus: "New" });
ShowClientToastr('False', 'False', 'toast-bottom-right', 'True', 'success', 'Template migration completed' + data.result, 'CAM - Contract Staff');
}
});
}
else {
ShowClientToastr('False', 'False', 'toast-bottom-right', 'True', 'error', 'Please select xls/xlsx file.', 'CAM - Contract Staff');
}
});
});
function test() {
$("#fuPDFAdd").click();
}
Something like this will work, I did wrap the file upload code to a separate function there, and make it to call this new function from your event listeners.
function uploadTheFile() {
console.log("tst1");
var file = this.files[0];
fileName = file.name;
size = file.size;
type = file.type;
if (type.toLowerCase() == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { //I just want pdf files and only want to show
var formData = new FormData($('#frmUplaodFileAdd')[0]);
$.ajax({
url: "UploadFile", //Server script to process data
type: 'POST',
async: false,
xhr: function() { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) { // Check if upload property exists
myXhr.upload.addEventListener('progress',
progressHandlingFunction, false); // For handling the progress of the upload
}
return myXhr;
},
data: formData,
//Options to tell jQuery not to process data or worry about content-type.
cache: false,
contentType: false,
processData: false,
success: function(data) {
grdStaffAddition.PerformCallback({
transStatus: "New"
});
ShowClientToastr('False', 'False', 'toast-bottom-right', 'True', 'success', 'Template migration completed' + data.result, 'CAM - Contract Staff');
}
});
} else {
ShowClientToastr('False', 'False', 'toast-bottom-right', 'True', 'error', 'Please select xls/xlsx file.', 'CAM - Contract Staff');
}
}
$("#fuPDFAdd").change(function() {
uploadTheFile();
});
function test() {
uploadTheFile();
}
I'm developing a small function for an image-upload. This image-upload resizes selected pictures on the client and upload the resized image.
This works, but the browser will hang a lot between "resizes-functionality".
This is my code:
function manageImage(file) {
if (!file) return;
var mime = file.type;
var src = URL.createObjectURL(file);
loadImage.parseMetaData(file, function (data) {
var options = { maxWidth: 1920, maxHeight: 1920, canvas: true };
if (data.exif) {
options.orientation = data.exif.get('Orientation');
}
loadImage(file,
function (img, test) {
loaded++;
var formData = new FormData();
formData.append("image", dataURI);
$.ajax({
url: "/URL",
data: formData,
cache: false,
contentType: false,
processData: false,
async: false,
type: "POST",
success: function (resp) {
}
}).error(function () {
}).done(function () {
if (loaded < checkedFiles.length) {
manageImage(files[loaded]);
} else {
//FINISHED
}
});
},
options);
});
}
manageImage(files[0]);
This funcition is recursive, because i had some problems with the iteration (browser-hang, memory and cpu-usage).
Additionally, i'm using this library for EXIF-Data and correct orientation on mobile phones:
https://github.com/blueimp/JavaScript-Load-Image
With one or two selected pictures (e.g. 7MB) it works perfect, but i want to upload maybe 50 pictures.
It would be great if someone can give me a clue?!
var files = [];
$(document).ready(function (){
dropArea = document.getElementById("droparea");
});
// when we drag and drop files into the div#droparea
dropArea.addEventListener("drop", function (evt) {
files = evt.dataTransfer.files;
}, false);
function uploadFiles(stepX) {
var url = "/ajax/uploadfiles.php";
var type = "POST";
if (files.length > 0) {
var data = new FormData(); // we use FormData here to send the multiple files data for upload
for (var i=0; i<files.length; i++) {
var file = files[i];
data.append(i, file);
}
//start the ajax
return $.ajax({
//this is the php file that processes the data and send mail
url: url,
//POST method is used
type: type,
//pass the data
data: data,
//Do not cache the page
cache: false,
// DO NOT set the contentType and processData
// see http://stackoverflow.com/a/5976031/80353
contentType: false,
processData: false,
//success
success: function (json) {
//if POST is a success expect no errors
if (json.error == null && json.result != null) {
data = json.result.data;
// error
} else {
alert(json.error);
}
}
});
}
return {'error' : 'No files', 'result' : null};
}
How do I track the progress of the file upload if I want to retain this method to upload files to server?
Note the comment with #TODO
//start the ajax
return $.ajax({
//this is the php file that processes the data and send mail
url: url,
//POST method is used
type: type,
//pass the data
data: data,
//Do not cache the page
cache: false,
//#TODO start here
xhr: function() { // custom xhr
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){ // check if upload property exists
myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // for handling the progress of the upload
}
return myXhr;
},
//#TODO end here
// DO NOT set the contentType and processData
// see http://stackoverflow.com/a/5976031/80353
contentType: false,
processData: false,
Add a standalone function that updates the progress.
function updateProgress(evt) {
console.log('updateProgress');
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
console.log(percentComplete);
} else {
// Unable to compute progress information since the total size is unknown
console.log('unable to complete');
}
}
From https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest > Monitoring progress