progress bar for Multiple file upload using Html5 - javascript

When I use progress event, I can update the progress bar for one uploading request:
function uploadFile(file) {
fileid=md5(file.name);
if {xhr[fileid] ;== undefined} {
xhr[fileid] = new XMLHttpRequest();
xhr[fileid].open('POST',' {% url upload %}', true);
xhr[fileid].setRequestHeader("X-File-Name", file.name);
xhr[fileid].setRequestHeader("X-File-id", fileid);
xhr[fileid].upload.addEventListener('progress', onprogressHandler, false);
xhr[fileid].upload.addEventListener('load',oncompleteHandler,false);
xhr[fileid].send(file);
}
function onprogressHandler(event) {
var percent = event.loaded/event.total*100;
var $target = $(event.target);
console.log(uploadHolder[fileid]);
uploadHolder[fileid].find(".upload-completed").css('width',percent+'%');
console.log('Upload progress: ' + percent + '%');
}
However, when I sent out more than 2 files upload requests at same time, Only the progress bar for the last file will be changed.
How do I determine which file upload request the event is attached to?
Update:
if I declare the fileid as local variable for uploadFile like var fileid, I cannot access fileid in the event handler. Using 'this' in the event handler give me the XMLHttpRequestUpload object.

You should look for "closure" concept for javascript. After that you'll understand the error. And this concept is so important i think, you should learn it :)

Related

web worker containing xhr object with upload progress event handler

I'm trying to create a worker that uploads file attached with event handler that will update progress bar in my html page. the upload is already working fine in the worker.
I know that web worker has no access to DOM objects, which is where all my progress bars are. so, I'm wondering if there's any work around? I want to do the uploads in worker, but I also want the progress tracking. I'll be uploading several file in parallel, so, each worker (upload) will have its own progress bar.
is this doable? or should I let go of web worker altogether and choose different design?
this is what's inside my worker
onmessage = e => {
var xhr = new XMLHttpRequest();
xhr.addEventListener('progress', function(e) {
var done = e.position || e.loaded, total = e.totalSize || e.total;
console.log('xhr progress: ' + (Math.floor(done/total*1000)/10) + '%');
}, false);
if ( xhr.upload ) {
xhr.upload.onprogress = function(e) {
var done = e.position || e.loaded, total = e.totalSize || e.total;
console.log('xhr.upload progress: ' + done + ' / ' + total + ' = ' + (Math.floor(done/total*1000)/10) + '%');
};
}
xhr.onreadystatechange = function(e) {
if ( 4 == this.readyState ) {
console.log(['xhr upload complete', e]);
}
};
xhr.open('post', url, true);
xhr.setRequestHeader("Content-Type","multipart/form-data");
let formData = new FormData();
formData.append("thefile", e.data.payload);
xhr.send(formData)
}
I already prepared some event handler, but currently, it's just logging.
Thanks
The onmessage events includes a .source property. This is how you send data back to the client. Inside your progress event listener you would add something like:
e.source.postMessage({uploadName: <unique name>, progress: done});
Watch out, though. You use e as both the onmessage handler data and the progress event handler. I would recommend making the names of the two unique.
Then in your page you listen for the message:
window.addEventListener('message', (data) => {
// ... read data.progress and send it to the right place on the page
}

How to show a spinner while making an HTTP request (Appcelerator)

Currently, I am trying to show a spinner while making an HTTP request that will end when the call completes. I have built several different spinners but all stop animation the second the call begins.
var spinnerArray = [];
for (var i = 0; i < 20; i++) {
spinnerArray.push('/images/preloaderGif/preloader'+ ("0" + i).slice(-2) + '.gif');
}
$.spinner.images = spinnerArray;
$.spinner.duration = "200";
$.spinner.repeatCount = "0";
spin();
function spin(){
$.spinner.start();
callHTTP() //Prewritten function
Ti.App.addEventListener('callEnd', function(e){
$.spinner.stop();
});
}
This results in the spinner never appearing. Taking the call out or nesting it within a timeout causes the spinner to spin infinitely, or until the timeout ends.
Is there a way to have the spinner continue to spin through the call?
Actually, there's a far better & super easy way to show an indicator. Just follow below steps.
Download this widget Loading Indicator Widget & add it to your project in app->widgets folder. Create widget folder if it doesn't exist.
Add this line "nl.fokkezb.loading" : "*" into your app->config.json file within dependencies dictionary as shown in below screenshot.
Add this line Alloy.Globals.loading = Alloy.createWidget("nl.fokkezb.loading"); in your alloy.js file
Finally, you can use this code to show/hide indicator properly while calling HTTP requests.
function callHTTP() {
if (!Ti.Network.online) {
return;
}
Alloy.Globals.loading.show();
var xhr = Ti.Network.createHTTPClient({
onerror : function(e) {
Alloy.Globals.loading.hide();
},
onload : function(e) {
Alloy.Globals.loading.hide();
// run your additional code here
},
});
xhr.open("GET", url);
xhr.send();
}
callHTTP();
Using this widget, you won't need to write long, error-prone codes for different projects. Just add this widget & you can show/hide loading indicator with just 2 lines of code.
Remember one thing that XHR error/success callbacks are the only places where you can write code to hide the indicators as you can never be sure when the HTTP request will complete.
You could use an ActivityIndicator : http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.ActivityIndicator
$.activityIndicator.show();
var xhr = Ti.Network.createHTTPClient({
onerror : function(e) {
// code
$.activityIndicator.hide();
},
onload : function(e) {
// code
$.activityIndicator.hide();
},
});
xhr.open("GET", url);
xhr.send();

Can i do a scheduled task programming with javascript?

I want to do a sheduled task for every day.I have multiple servers and i want to automate the upload of html file to my other servers.In this case i have on the same folder my html and my script.js.Im currently using ajax to upload the html file but i want to do that without interference.Here is my javascript.
$(function(){
$("#drop-box").click(function(){
$("#upl").click();
});
// To prevent Browsers from opening the file when its dragged and dropped on to the page
$(document).on('drop dragover', function (e) {
e.preventDefault();
});
// Add events
$('input[type=file]').on('change', fileUpload);
// File uploader function
function fileUpload(event){
$("#drop-box").html("<p>"+event.target.value+" uploading...</p>");
files = event.target.files;
var data = new FormData();
var error = 0;
for (var i = 0; i < files.length; i++) {
var file = files[i];
console.log(file.type);
if(!file.type.match('html.*')) {
$("#drop-box").html("<p> Html only. Select another file</p>");
error = 1;
}else if(file.size > 1048576){
$("#drop-box").html("<p> Too large Payload. Select another file</p>");
error = 1;
}else{
data.append('html', file, file.name);
}
}
if(!error){
var xhr = new XMLHttpRequest();
xhr.open('POST', 'upload.php', true);
xhr.send(data);
xhr.onload = function () {
if (xhr.status === 200) {
$("#drop-box").html("<p> File Uploaded. Select more files</p>");
} else {
$("#drop-box").html("<p> Error in upload, try again.</p>");
}
};
}
}
This script work fine with my server side, but i want to be able to perform this html upload every day.Is this possible ? what about SetInterval and SetTimeout ?
You can schedule tasks with JavaScript so that they are executed in specific intervals. But you can not upload files from the local system to the server:
JavaScript can't start file transfers on it's own due to security reasons and always needs manual user interaction to do this.
The reason why your above script works is because fileUpload() is orginally triggered by the user. As soon as you use timeout() or interval(), the browser detects that the operation was not triggered by the user and won't allow you to upload user data.

Uniquely identify an upload

I'm uploading files using the following code:
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.open("POST", requestUrl, true);
xhr.send(f);
Note that I'm attaching a listener to upload progress:
function uploadProgress(evt)
{
// Which upload was it?
}
Here's the question, if I have multiple uploads happening at the same time, and they are sharing the same event handler, how can I figure out which upload triggered the event?
Try to wrap it as a Control?
var uploadProgress = function(uploadObj, event) {
// Do somthing about uploadObj
}
// Target maybe object or string, whatever you want
var Uploader = function(target) {
var xhr = new XMLHttpRequest();
var handler = uploadProgress.bind(this, target);
xhr.upload.addEventListener("progress", handler, false);
xhr.open("POST", target, true);
xhr.send(f);
}
The .bind will return a new function, when execute the new function, it'll:
Use this here, the Uploader as its context.
Execute uploadProgress and pass target as first argument, so the evt given by progess event will be passed to the 2nd param in uploadProgress.

Upload Image Using AJAX with Progress Indicator

I am trying to upload an image using AJAX. I have the local URL of my image
and I want to pass that image as a file to the web service to upload.
Suppose i have the local file URL as : file:///accounts/1000/shared/camera/IMG_00000322.jpg
Now using AJAX I want to pass this to webservice,
What will be the best way to do this? I also want show the progress while uploading
Using php in server side.
uploadImage : function(myImageUrl,chatId){
var formData = new FormData();
formData.append("chatId", chatId);
formData.append("fileimage", myImageUrl);
$.ajax(
{
type:"POST",
url:"http://suresh.sp.in/butler/public/uploadimage/getimage",
contentType:"image/png",
dataType:"json",
data:formData,
success:function(uploaded){
console.info(uploaded.status);
},
error:function(error){
console.info(error);
}
});
}
I used that snippet on several of my websites, it handles Multiples files upload, drag and drop, and a progress bar.
HTML
You will need a container to drop your batch of files, in our case it will be #output, and a list of files.
JS
First we will push the dataTransfer to jQuery's event and bind the drop event.
$(document).ready(function(){
// We add the dataTransfer special property to our jQuery event
$.event.props.push("dataTransfer");
// We bind events for drag and drop
$('#output').bind({
"dragenter dragexit dragover" : do_nothing,
drop : drop
});
});
// stop event propagation
function do_nothing(evt){
evt.stopPropagation();
evt.preventDefault();
}
Then we build our update progress function
// Progress bar update function
function update_progress(evt,fic) {
var id_tmp=fic.size;
//id_tmp help us keep track of which file is uploaded
//right now it uses the filesize as an ID: script will break if 2 files have the
// same size
if (evt.lengthComputable) {
var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
if (percentLoaded <= 100) {
$('#'+id_tmp+' .percent').css('width', percentLoaded + '%');
$('#'+id_tmp+' .percent').html(percentLoaded + '%');
}
}
}
Last but not least our drop function
function drop(evt){
do_nothing(evt);
var files = evt.dataTransfer.files;
// Checking if there are files
if(files.length>0){
for(var i in files){
// if its really a file
if(files[i].size!=undefined) {
var fic=files[i];
// We add a progress listener
xhr = jQuery.ajaxSettings.xhr();
if(xhr.upload){
xhr.upload.addEventListener('progress', function (e) {
update_progress(e,fic);
},false);
}
provider=function(){ return xhr; };
// We build our FormData object
var fd=new FormData;
fd.append('fic',fic);
// For each file we build and Ajax request
$.ajax({
url:'/path/to/save_fic.php',
type: 'POST',
data: fd,
xhr:provider,
processData:false,
contentType:false,
complete:function(data){
//on complete we set the progress to 100%
$('#'+data.responseText+' .percent').css('width', '100%');
$('#'+data.responseText+' .percent').html('100%');
}
});
// for each file we setup a progress bar
var id_tmp=fic.size;
$('#output').after('<div class="progress_bar loading" id="'+id_tmp+'"><div class="percent">0%</div></div>');
$('#output').addClass('output_on');
// We add our file to the list
$('#output-listing').append('<li>'+files[i].name+'</li>');
}
}
}
}
That method doesn't work in IE9 or below.
Hope it helped!
Source(in french)
Some infos on progress tracking using XMLHttpRequest
Some infos on the datatransfer prop
EDIT:
PHP
From the server side you can handle the files normally using $_FILES etc...
In order to set the progress to 100% in the complete function your php script must echo the filesize.

Categories

Resources