Managing Progress Bars for Multiple File Upload - javascript

So I am using a ajax to upload multiple files. Everything seems to be working like a charm... I just can't get to make my progress bars to work ...
Any help would be really appreciated. Thanks.
var images = document.getElementById('images');
for(var i=0;i<images.files.length;i++) {
var formData = new FormData();
var image = images.files[i];
formData.append('image', image);
formData.append('order_id', document.getElementById('order_id').value);
var xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","/pictures/uploadImage");
xmlhttp.send(formData);
xmlhttp.upload.addEventListener('progress', function(e){
document.getElementById("image_"+i+"_progress").value = Math.ceil(e.loaded/e.total)*100;
}, false);
}
I am basically uploading images individually .. I figured that would help me track the progress bars better ... Perhaps there's another approach.

According to [MDN][1]:
Note: You need to add the event listeners before calling open() on the request. Otherwise the progress events will not fire.
So, combining this knowledge with Engin's answer, you could do like this:
const images = document.getElementById('images');
const completedCount = 0; // added for loadend scenario
const length = images.files.length;
for (let i = 0; i < length; i++) {
const formData = new FormData();
const image = images.files[i];
formData.append('image', image);
formData.append('order_id', document.getElementById('order_id').value);
const xmlhttp = new XMLHttpRequest();
(elId => {
xmlhttp.upload.addEventListener('progress', e => {
document.getElementById('image_' + elId + '_progress').value = Math.ceil(e.loaded / e.total) * 100;
}, false);
})(i); // to unbind i.
// --- added for loadend scenario. ---
xmlhttp.addEventListener('loadend', () => {
completedCount++;
if (completedCount == length) {
// here you should hide your gif animation
}
}, false);
// ---
xmlhttp.open('POST', '/pictures/uploadImage');
xmlhttp.send(formData);
}
UPDATE:
To catch the event when all files are uploaded you may use loadend events. I've updated my code (see comments), I'm not sure this is a correct way though.
[1]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress

i did not try but i think it works, because for loop finished before your post and "i"s value equal to images.files.length. sorry for terrible english
try this:
var images = document.getElementById('images');
for(var i=0;i<images.files.length;i++) {
getProgress(images.files[i],i);
}
function getProgress(image,order){
var formData = new FormData();
formData.append('image', image);
formData.append('order_id', document.getElementById('order_id').value);
var xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","/pictures/uploadImage");
xmlhttp.send(formData);
xmlhttp.upload.addEventListener('progress', function(e){
document.getElementById("image_"+order+"_progress").value = Math.ceil(e.loaded/e.total)*100;
}, false);
}

You can include another function.
function upload(ProgressbarId){
/*
.
.
.
some code
*/
xmlhttp.upload.addEventListener("progress", function(evt){uploadProgress(evt,ProgressbarId);}, false);
}
function uploadProgress(evt,ProgressbarId) {
if (evt.lengthComputable) {
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
set_Progressbar(ProgressbarId,percentComplete);
}
}
}

Related

How do I fetch all images in a folder with AJAX using pure JS?

I'm trying to get all the images in a folder with an AJAX request (for use in an image slider). I've found this jQuery solution which works perfectly fine, except that it uses jQuery. What would a pure JS equivalent look like? (i.e. XMLHttpRequest)
Thanks to #FZs help this is what I ended up with. Thank you!
var xhr = new XMLHttpRequest();
xhr.open("GET", "/img", true);
xhr.responseType = 'document';
xhr.onload = () => {
if (xhr.status === 200) {
var elements = xhr.response.getElementsByTagName("a");
for (x of elements) {
if ( x.href.match(/\.(jpe?g|png|gif)$/) ) {
let img = document.createElement("img");
img.src = x.href;
document.body.appendChild(img);
}
};
}
else {
alert('Request failed. Returned status of ' + xhr.status);
}
}
xhr.send()
You can do it without jQuery! Maybe with more code, but this should work (adapted from this post)):
var folder = "images/";
var ajax=new XMLHttpRequest()
ajax.open("GET",folder,true)
ajax.onload=function () {
var elements=(new DOMParser()).parseFromString(ajax.responseText,"text/html").getElementsByTagname("A")
for(x of elements){
if(request.status[0]==2 && x.href.match(/\.(jpe?g|png|gif)$/)) {
let img=document.createElement("IMG")
img.src=folder+x.href
document.body.appendChild(img);
}
};
}
ajax.send()
Or, you can force XMLHttpRequest to parse document (idea from #Rainman's comment):
ajax.responseType = "document"
So the code becomes to the following:
var folder = "images/";
var ajax=new XMLHttpRequest()
ajax.open("GET",folder,true)
ajax.onload=function () {
ajax.responseType="document"
var elements=ajax.responseText.getElementsByTagname("A")
for(x of elements){
if(request.status[0]==2 && x.href.match(/\.(jpe?g|png|gif)$/)) {
let img=document.createElement("IMG")
img.src=folder+x.href
document.body.appendChild(img);
}
};
}
ajax.send()

Pass image src to function instead of files

So I have a webpage with two image elements. It is basically a website where you upload an image and it encrypts a secret massage with steganography. I want to show the difference that is not otherwise visible and I found Resemble.js which is a library to compare images. It gets two files as arguments and I would like to use my image sources instead of files since I don't want to save the images generated.
To sum up, I want to get rid of the requests and get my images via sources in the HTML but I don't know how to get it to work with Resemble.js since it accepts only files.
How the second image is generated:
cover.src = steg.encode(textarea.value, img, {
"width": img.width,
"height": img.height
});
The JavaScript working with files:
(function () {
var xhr = new XMLHttpRequest();
var xhr2 = new XMLHttpRequest();
var done = $.Deferred();
var dtwo = $.Deferred();
try {
xhr.open('GET', 'static/original.png', true);
xhr.responseType = 'blob';
xhr.onload = function (e) { done.resolve(this.response); };
xhr.send();
xhr2.open('GET', 'static/encoded.png', true);
xhr2.responseType = 'blob';
xhr2.onload = function (e) { dtwo.resolve(this.response); };
xhr2.send();
} catch (err) {
alert(err);
}
$('#example-images').click(function () {
$.when(done, dtwo).done(function (file, file1) {
if (typeof FileReader === 'undefined') {
resembleControl = resemble('./static/original.png')
.compareTo('./static/encoded.png')
.onComplete(onComplete);
} else {
resembleControl = resemble(file)
.compareTo(file1)
.onComplete(onComplete);
}
});
return false;
});
}());

sending arguments from one function to another through event handler

I have two functions here, the first one is triggered by a button and it is meant to trigger a second function which will change the inner html of that first buttons accompanying html area.
My problem is how to pass the arguments from the first function INTO the second one to the button and textfield have the same idnumber.
function doLoad(idnumber, id) {
var file = _(id).files[0];
_("Btn1_QP_"+idnumber).style.display = "none";
_("Display_QP_"+idnumber).innerHTML = "Image uploading......";
var formdata = new FormData();
formdata.append("stPic", file);
var ajax = new XMLHttpRequest();
ajax.addEventListener("load", completeHandler, false);
ajax.open("POST", "pho_stem3.php");
ajax.send(formdata);
}
function completeHandler(event) {
_("Display_QP").innerHTML = 'wahooo';
}
}
In function doLoad idnumber is given by the button and used to identify the proper button with("Btn1_QP_"+idnumber)
how can i achieve this same selective ability in the second function completeHandler in the event listener.
I have tried
ajax.addEventListener("load", completeHandler(idnumber), false);
ajax.addEventListener("load", ("completeHandler"+idnumber), false);
both dont work. how can i preserve and transmit the original argument from doLoad...
You can pass the same id number in response of ajax like this:
function doLoad(idnumber, id) {
var file = _(id).files[0];
_("Btn1_QP_" + idnumber).style.display = "none";
_("Display_QP_" + idnumber).innerHTML = "Image uploading......";
var formdata = new FormData();
formdata.append("stPic", file);
var ajax = new XMLHttpRequest();
ajax.open("POST", "pho_stem3.php");
ajax.send(formdata);
ajax.onreadystatechange = function() {
if (ajax.readyState == 4) {
completeHandler(idnumber);
}
}
}
function completeHandler(idnumber) {
_("Display_QP_" + idnumber).innerHTM = 'wahooo';
}

Is it possible to share an image to facebook using a data URI?

I have several canvases positioned over each other that merge into one as data URI. Everything works fine and I can get the composite image to show up on the page, but the other funcitonality I require is to create the URI and then share to facebook. I wanted to try to do this without sending to the server and do it all client side.
the code isn't necessary to the problem but if you want to see it
<ul class="button-group even-2">
<li><span id='merge-canvas' class="button expand">Save Image</span></li>
<li><span id='share-facebook' class="button expand facebook" >Share</span></li>
</ul>
with the javascript looking like this.
// DROPBOX AND FILE READER
function noopHandler(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function drop(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files;
var count = files.length;
// Only call the handler if 1 or more files was dropped.
if (count > 0) {
}
handleFiles(files);
}
function handleFiles(files) {
var file = files[0];
document.getElementById("droplabel").innerHTML = "Processing " + file.name;
var reader = new FileReader();
// init the reader event handlers
reader.onloadend = handleReaderLoadEnd;
// begin the read operation
reader.readAsDataURL(file);
}
function handleReaderLoadEnd(evt) {
// basically clears and redraws the face canvas on load of the users image
document.getElementById("droplabel").innerHTML = "Picture Added Successfully!";
var $canvas = $('canvas');
ctx = $canvas[0].getContext('2d');
face = new Image();
face.onload = function() {
ctx.drawImage(face, 0, 0, 500, (face.height/face.width) * 500);
}
face.src = evt.target.result;
return face;
}
function initializeDropbox() {
var dropbox = document.getElementById("dropbox")
// adds different events for the dropbox and points to the relevant function
dropbox.addEventListener("dragenter", noopHandler, false);
dropbox.addEventListener("dragexit", noopHandler, false);
dropbox.addEventListener("dragover", noopHandler, false);
dropbox.addEventListener("drop", drop, false);
}
which produces a really really long data URI!
Any ideas to accomplish the share?
You can post an image via URL or multipart/form-data in the source parameter:
https://developers.facebook.com/docs/graph-api/reference/v2.1/user/photos
/* make the API call */
FB.api(
"/me/photos",
"POST",
{
"source": "{image-data}"
},
function (response) {
if (response && !response.error) {
/* handle the result */
}
}
);

Why might XMLHttpRequest ProgressEvent.lengthComputable be false?

I'm trying to implement a upload progress bar the HTML5 way, by using the XMLHttpRequest level 2 support for progress events.
In every example you see, the method is to add an event listener to the progress event like so:
req.addEventListener("progress", function(event) {
if (event.lengthComputable) {
var percentComplete = Math.round(event.loaded * 100 / event.total);
console.log(percentComplete);
}
}, false);
Such examples always seem to assume that event.lengthComputable will be true. After all, the browser knows the length of the request it's sending, surely?
No matter what I do, event.lengthComputable is false. I've tested this in Safari 5.1.7 and Firefox 12, both on OSX.
My site is built using Django, and I get the same problem on my dev and production setups.
The full code I'm using to generate the form upload is shown below (using jQuery):
form.submit(function() {
// Compile the data.
var data = form.serializeArray();
data.splice(0, 0, {
name: "file",
value: form.find("#id_file").get(0).files[0]
});
// Create the form data.
var fd = new FormData();
$.each(data, function(_, item) {
fd.append(item.name, item.value);
});
// Submit the data.
var req = new XMLHttpRequest();
req.addEventListener("progress", function(event) {
if (event.lengthComputable) {
var percentComplete = Math.round(event.loaded * 100 / event.total);
console.log(percentComplete);
}
}, false);
req.addEventListener("load", function(event) {
if (req.status == 200) {
var data = $.parseJSON(event.target.responseText);
if (data.success) {
console.log("It worked!")
} else {
console.log("It failed!")
}
} else {
console.log("It went really wrong!")
}
}, false);
req.addEventListener("error", function() {
console.log("It went really really wrong!")
}, false);
req.open("POST", "/my-bar/media/add/");
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
req.send(fd);
// Don't really submit!
return false;
});
I've been tearing my hair out for hours on this. Any help appreciated!
Hey I found the answer from #ComFreek:
I made the same mistake.
The line I wrote was:
xhr.onprogress = uploadProgress;
The correct one should be
xhr.upload.onprogress = uploadProgress;
take a look into this :
https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
xhr.upload.addEventListener('progress',function(e){}) will also work.
I also had problem with sending multiple big files using AJAX (xmlhttprequest).
Found a solution and here is whole script that I use.
All you need is to place next line in your HTML page:
<input type="file" multiple name="file" id="upload_file" onchange="handleFiles(this)">
and use next script:
<script type="text/javacript">
var filesArray;
function sendFile(file)
{
var uri = "<URL TO PHP FILE>";
var xhr = new XMLHttpRequest();
var fd = new FormData();
var self = this;
xhr.upload.onprogress = updateProgress;
xhr.addEventListener("load", transferComplete, false);
xhr.addEventListener("error", transferFailed, false);
xhr.addEventListener("abort", transferCanceled, false);
xhr.open("POST", uri, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText); // handle response.
}
};
fd.append('myFile', file);
// Initiate a multipart/form-data upload
xhr.send(fd);
}
function updateProgress (oEvent)
{
if (oEvent.lengthComputable)
{
var percentComplete = oEvent.loaded / oEvent.total;
console.log(Math.round(percentComplete*100) + "%");
} else {
// Unable to compute progress information since the total size is unknown
console.log("Total size is unknown...");
}
}
function transferComplete(evt)
{
alert("The transfer is complete.");
}
function transferFailed(evt)
{
alert("An error occurred while transferring the file.");
}
function transferCanceled(evt)
{
alert("The transfer has been canceled by the user.");
}
function handleFiles(element)
{
filesArray = element.files;
if (filesArray.length > 0)
{
for (var i=0; i<filesArray.length; i++)
{
sendFile(filesArray[i]);
}
filesArray = '';
}
}
</script>
Your result will be in console

Categories

Resources