I am trying to upload some large files to the server using XMLHttpRequest and file.slice.
I've manage doing this with the help of documentations and other various links.
Since uploading large file is a lengthily job, i would like to provide the user with a progress bar.
After some more readings i've come across on an example that, theoretically, does exactly what i need.
By taking the sample code and adapting it to my needs i reached
var upload =
{
blobs: [],
pageName: '',
bytesPerChunk: 20 * 1024 * 1024,
currentChunk: 0,
loaded: 0,
total: 0,
file: null,
fileName: "",
uploadChunk: function (blob, fileName, fileType) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.responseText) {
// alert(xhr.responseText);
}
}
};
xhr.addEventListener("load", function (evt) {
$("#dvProgressPrcent").html("100%");
$get('dvProgress').style.width = '100%';
}, false);
xhr.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var progress = Math.ceil(((upload.loaded + evt.loaded) / upload.total) * 100);
$("#dvProgressPrcent").html(progress + "%");
$get('dvProgress').style.width = progress + '%';
}
}, false);
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var progress = Math.ceil(((upload.loaded + evt.loaded) / upload.total) * 100);
$("#dvProgressPrcent").html(progress + "%");
$get('dvProgress').style.width = progress + '%';
}
}, false);
xhr.open('POST', upload.pageName, false);
xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.setRequestHeader("X-File-Name", fileName);
xhr.setRequestHeader("X-File-Type", fileType);
xhr.send(blob);
},
upload: function (file) {
var start = 0;
var end = 0;
var size = file.size;
var date = new Date();
upload.fileName = date.format("dd.MM.yyyy_HH.mm.ss") + "_" + file.name;
upload.loaded = 0;
upload.total = file.size;
while (start < size) {
end = start + upload.bytesPerChunk;
if (end > size) {
end = size;
}
var blob = file.slice(start, end);
upload.uploadChunk(blob, upload.fileName, file.type);
start = end;
upload.loaded += start;
}
return upload.fileName;
}
};
The call is like (without the validations)
upload.upload(document.getElementById("#upload").files[0]);
My problem is that the progress event doesn't trigger.
I've tried xhr.addEventListener and with xhr.upload.addEventListener (each at a time and both at a time) for the progress event but it never triggers. The onreadystatechange and load events trigger just fine.
I would greatly appreciate help with what i am doing wrong
Update
After many attempts i've manage to simulate a progress but i've ran into another problem: Chrome's UI is not updating during the upload.
The code looks like this now
var upload =
{
pageName: '',
bytesPerChunk: 20 * 1024 * 1024,
loaded: 0,
total: 0,
file: null,
fileName: "",
uploadFile: function () {
var size = upload.file.size;
if (upload.loaded > size) return;
var end = upload.loaded + upload.bytesPerChunk;
if (end > size) { end = size; }
var blob = upload.file.slice(upload.loaded, end);
var xhr = new XMLHttpRequest();
xhr.open('POST', upload.pageName, false);
xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.setRequestHeader("X-File-Name", upload.fileName);
xhr.setRequestHeader("X-File-Type", upload.file.type);
xhr.send(blob);
upload.loaded += upload.bytesPerChunk;
setTimeout(upload.updateProgress, 100);
setTimeout(upload.uploadFile, 100);
},
upload: function (file) {
upload.file = file;
var date = new Date();
upload.fileName = date.format("dd.MM.yyyy_HH.mm.ss") + "_" + file.name;
upload.loaded = 0;
upload.total = file.size;
setTimeout(upload.uploadFile, 100);
return upload.fileName;
},
updateProgress: function () {
var progress = Math.ceil(((upload.loaded) / upload.total) * 100);
if (progress > 100) progress = 100;
$("#dvProgressPrcent").html(progress + "%");
$get('dvProgress').style.width = progress + '%';
}
};
Update 2
I've managed to fix it and simulate a progress bar that works in chrome too.
i've updated previous code sample with the one that works.
You can make the bar 'refresh' more often by reducing the size of the chunk uploaded at a time
Tahnk you for your help
You have to use the FormData object to wrap the file into a multipart/form-data post data object: var formData = new FormData(); formData. append("thefile", file); xhr. send(formData);
As stated in https://stackoverflow.com/a/3694435/460368, you could do :
if(xhr.upload)
xhr.upload.onprogress=upload.updateProgress;
and
updateProgress: function updateProgress(evt)
{
if (evt.lengthComputable) {
var progress = Math.ceil(((upload.loaded + evt.loaded) / upload.total) * 100);
$("#dvProgressPrcent").html(progress + "%");
$get('dvProgress').style.width = progress + '%';
}
}
There is my solution:
function addImages(id) {
var files = $("#files").prop("files");
var file = files[loopGallery];
var cList = files.length;
var fd = new FormData();
fd.append("file", file);
fd.append("galerie", id);
var xhr = new XMLHttpRequest();
xhr.open("POST", "moduls/galerie/uploadimages.php", true);
xhr.upload.onprogress = function(e) {
var percentComplete = Math.ceil((e.loaded / e.total) * 100);
$("#progress").css("display","");
$("#progressText").text((loopGallery+1)+" z "+cList);
$("#progressBar").css("width",percentComplete+"%");
};
xhr.onload = function() {
if(this.status == 200) {
$("#progressObsah").load("moduls/galerie/showimages.php?ids="+id);
if((loopGallery+1) == cList) {
loopGallery = 0;
} else {
$("#progressBar").css("width", "0%");
loopGallery++;
addImages(id);
}
}
}
if(cList > 0) {
xhr.send(fd);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With