Progress Bar in ajax while uploading 2 files or more - javascript

Hi Im trying to upload a 2 file or more, my problem is my progress bar will say 100% because of the small file being uploaded first, then its going back to the percent of the large file.. My question is how can I have a same progress if i have many files being uploaded?
$('body').on('change', 'input:file.gallery_images', function(event)
{
event.preventDefault();
var data = new FormData();
data.append('id', $("#id").val());
var count = $(this)[0].files.length;
$.each($(this)[0].files, function(i, file)
{
data.append('userfile', file);
$.ajax(
{
type: "POST",
url: href+path+"/imagens/store",
data: data,
mimeType: 'multipart/form-data',
contentType: false,
cache: false,
processData: false,
dataType: "json",
xhr: function()
{
var _xhr = $.ajaxSettings.xhr();
_xhr.addEventListener('progress', function (event) { }, false);
if (_xhr.upload)
{
_xhr.upload.onprogress = function(event)
{
var percent = 0;
if (event.lengthComputable)
{
var position = event.position || event.loaded;
var total = event.totalSize || event.total;
percent = Math.ceil(position / total * 100);
}
$("#progress-bar").width(percent + '%');
};
}
return _xhr;
},
beforeSend: function()
{
$("#progress").fadeIn('slow');
$("#progress-bar").width('0%');
},
success: function(data)
{
if(data.gallery)
{
if($(".alert").length > 0)
{
$(".alert").hide('slow').remove();
$("#droppable").show('slow');
}
$('.gallery').fadeTo('300', '0.5', function () {
$(this).html($(this).html() + data.gallery).fadeTo('300', '1');
});
}
$("#progress").fadeOut('slow');
}
});
});
});

Ok, first thing I noticed is that you're adding the file to the 'data' variable inside your $.each... but that means the first POST contains the first image, the second POST contains the first and the second, and so on. I think you should this part inside your $.each:
var data = new FormData();
data.append('id', $("#id").val());
Ok, so, to solve your problem: Before sending anything, go through them and sum their size. You'll also need to store the progress for each file individually, so start it as zero:
var sumTotal = 0;
var loaded = [];
for (var i = 0, list = $(this)[0].files; i < list.length; i++) {
sumTotal += list[i].size;
loaded[i] = 0;
}
Inside your onprogress, instead of comparing the event.position with the event.totalSize, you'll store this position on your 'loaded' array, sum all your array, and then compare it to your sumTotal.
loaded[i] = event.position || event.loaded;
var sumLoaded = 0;
for (var j = 0; j < loaded.length; j++) sumLoaded += loaded[j];
percent = Math.ceil(sumLoaded * 100/sumTotal);
;)

Related

Is it possible to store base64 of a file in javascript object and send it to backend using ajax?

I am just trying to upload image file in base64 format by storing it in a js object. But the problem here is the object property 'baseData' doesn't fill with the DataURL of the image. If the way I mentioned below is possible, please suggest the solution to fill the 'baseData' property.
What I am doing is storing the 'type' (image or video, not extensions) and DataURL of the file in the object(fileDataObject) and pushing the object to an array(blobData), and returning the same at the end of the function.
Thanks in advance
var filesAccept = filesValidator($("#file-upload")[0].files);
if(filesAccept !== false){
var fd = new FormData();
fd.append("files", filesAccept)
$.ajax({
type: "POST",
url: "receiver.php",
data: fd,
processData: false,
contentType: false,
dataType: "text",
success: function (result) {
console.log(result);
},
});
}
function filesValidator(f) {
if (f.length === 0) {
$("#error-info").text("Please select some images or videos.");
return false;
} else if(f.length !== 0) {
var blobData = [];
var fileType;
$("#error-info").text("");
var n = 10;
if (f.length < 10) {// checking if files count less than 10
n = f.length;
}
for (let i = 0; i < n; i++) {
var reader = new FileReader();
fileType = f[i].type.split("/");
if(fileType[1] === "gif"){
return false;
} else if (fileType[0] === "image") {// if file is images
reader.onload = function(e) {
var src = e.target.result.split(",")[1];
console.log(src);
var fileDataObject = {
baseData : src,
type : "image"
};
blobData.push(JSON.stringify(fileDataObject));
}
reader.readAsDataURL(f[i]);
} else if(fileType[0] === "video") { //if file is video
reader.onload = function(e) {
var src = e.target.result.split(",")[1];
var fileDataObject = {
baseData : src,
type : "video"
};
blobData.push(JSON.stringify(fileDataObject));
}
reader.readAsDataURL(f[i]);
}
console.log(blobData);
}
return blobData;
}
}

I can't send data to the server using AJAX

The situation is as follows: I upload a drag and drop image to the server. Everything would have been simpler, but first you need to embed the dropped image into the DOM tree, after which it can be removed from there, and the rest need to be sent to the server. At the drop event, I add the file itself and the picture className to the associative array. After the user is ready to send all the remaining pictures to the server, I add the files that have the classes of the remaining pictures as the key to the new array and form FormData of it. But the server does not receive files. Help!
code:
var arr = new Map;
//create a associative array.
dnd.addEventListener('drop', e => {
e.preventDefault();
var image_ = e.dataTransfer.files;
.....
//embed dropped image into the DOM tree
const text = e.dataTransfer.getData("text");
if (text) {
let img = document.createElement('img');
img.src = text;
$('#container_').append(img);
}
else {
const files = e.dataTransfer.files;
[].map.call(files, file => {
if (file.type.match(/^image/)) {
let reader = new FileReader();
reader.onload = file => {
let img = document.createElement('img');
img.className = "droppedPhoto" + Math.random();
img.setAttribute("widt", "200");
img.setAttribute("height", "200");
img.src = file.target.result;
let div = document.createElement('div');
$('#container_').append(div);
$('#container_').children().last().append(img);
arr.set(img.className, image_);
$('.sendPhotos > p > button').on('click', function () {
checkData(arr);
});
function checkData(array) {
var $arrOfImg = $('#container_ > div > img');
var $newArrayOfData =[];
for (var i = 0; i < $arrOfImg.length; i++) {
if (array.has($arrOfImg[i].className)) {
$newArrayOfData.push(array.get($arrOfImg[i].className));
}
}
createFormData($newArrayOfData);
}
function createFormData(images) {
var formImage = new FormData();
for (var i = 0; i < images.length; i++) {
formImage.append(key, images[i]);
}
uploadFormData(formImage);
}
function uploadFormData(formData) {
$.ajax({
url: '#Url.Action("PhotoSessionInfo", "Home")',
type: "POST",
xhr: function () {
var myXhr = $.ajaxSettings.xhr();
return myXhr;
},
data: formData,
contentType: 'multipart/form-data',
cache: false,
processData: false,
success: function (response) {
console.log("success");
$('#container_').html(response);
}
});
}

JQuery Ajax loop delay

i am trying to make a delay in my ajax data so the loop become a little bit slower !
and here is my code
$(document).ready(function (){
$('#button').click(function(){
$('#hide').show();
var data = $('#textarea').val();
var arrayOfLines = data.split("\n");
var track = JSON.stringify(arrayOfLines);
var item = "";
var lines = $('#textarea').val().split('\n');
here is the loop
for (var i = 0; i < lines.length; i++) {
item = lines[i];
$.ajax({
type: 'GET',
url: 'cookie.php',
dataType: 'html',
data: 'data=' + item+'&cookie='+track,
success: function(msg){
$('#results').append(msg);
}
});
}
});
Using recursion, you could put in a function sendToServer and pass through the array lines, starting index 0. The function will run from 0 to lines.length. This way you won't DDOS your server :)
If you really need some kind of arbitrary delay, you can include a timeout on the sendToServer function call - in the example it is set to 5 seconds.
var sendToServer = function(lines, index){
if (index > lines.length) return; // guard condition
item = lines[index];
if (item.trim().length != 0){
$.ajax({
type: 'GET',
url: 'cookie.php',
dataType: 'html',
data: 'data=' + item+'&cookie='+track,
success: function(msg){
$('#results').append(msg);
setTimeout(
function () { sendToServer(lines, index+1); },
5000 // delay in ms
);
}
});
}
else { sendToServer(lines, index+1); }
};
sendToServer(lines, 0);
Don't send request to server in for loop. It can take down the server. Instead of what you did , you can do this :
for (var i = 0; i < lines.length; i++) {
item = lines[i];
}
$.ajax({
type: 'GET',
url: 'cookie.php',
dataType: 'html',
data: 'data=' + item+'&cookie='+track,
success: function(msg){
$('#results').append(msg);
}
});
Use like this:
var timeDelay = 5000;
setTimeout(Function, timeDelay);

Getting a File's MD5 on Dropzone.js

I would like to calculate an MD5 checksum of every image uploaded with Dropzone.js, this way the user can safely remove the correct image (I calculate the MD5 Checksum in php part).
I need to create the MD5 hash with another library (FastMD5 or another one), and then send it along with the data when remove button is clicked.
For now:
$Dropzone.autoDiscover = false;
// Dropzone class:
var myDropzone = new Dropzone("div#dropzonePreview", {
maxFiles:5,
url: "up",
acceptedFiles: ".png,.jpg,.gif,.jpeg",
maxFilesize: 6,
uploadMultiple: true,
addRemoveLinks: true,
removedfile: function(file) {
var name = file.name;
var idform = document.getElementById('idform').value; //for me
var hash= md5(file); // not tested
$.ajax({
type: 'POST',
url: 'del.php',
data:"filename="+name+"&idform="+idform+"&hash="+hash,
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
}
});
The problem is that md5(file) is not working, I guess it isn't the data file, I tried to look for the data to calculate the hash but found nothing.
I'm sure there is a better way to do it, but I've made this and it's sending the right hash to my delete page (del.php), I've just realised that I will also need the hash to avoid the upload of the same file 2 times..
I've used SPARK-MD5.
Dropzone.autoDiscover = false;
// Dropzone class:
var myDropzone = new Dropzone("div#dropzonePreview", {
maxFiles:5,
url: "upload.php",
acceptedFiles: ".png,.jpg,.gif,.jpeg",
maxFilesize: 6,
uploadMultiple: true,
addRemoveLinks: true,
//to remove one file
removedfile: function(file) {
var name = file.name;
var idform = document.getElementById('idform').value; //for me
// START SPARKMD5
var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
chunkSize = 2097152, // Read in chunks of 2MB
chunks = Math.ceil(file.size / chunkSize),
currentChunk = 0,
spark = new SparkMD5.ArrayBuffer(),
fileReader = new FileReader();
fileReader.onload = function (e) {
console.log('read chunk nr', currentChunk + 1, 'of', chunks);
spark.append(e.target.result); // Append array buffer
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
console.log('finished loading');
// START DROPZONE PART
$.ajax({
type: 'POST',
url: 'del.php',
data:"filename="+name+"&idform="+idform+"&hash="+spark.end(), //spark.end is the MD5
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
// END DROPZONE PART
}
};
fileReader.onerror = function () {
console.warn('oops, something went wrong.');
};
function loadNext() {
var start = currentChunk * chunkSize,
end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
}
loadNext();
// END SPARKMD5
}
});
I'm not sure about the necessity of fileReader.onerror and load next.
Anyway it's working when the need is to send the hash when the "remove" button is clicked, but i'm still looking for a better way to compare md5 before uploading.

Difficulty in loading multiple images in a list view served by multiple xml files

I am developing a html application for Android and I am trying to load images in a list view. Data specific to list items is being served by multiple xml files. I am using ajax to load xml files and populate the list items. Problem I am facing here is that there are 164 list items. Hence, 164 images and 10 xml files to load. my loader function exhausts after two iterations. It does read the xml files but it's unable to dynamically create list items and populate them with images after two iterations. I believe it's due to stack limitations. I can't think of alternate solution. If somebody could suggest an alternate solution that will be highly appreciated. Below is my loader function. It's a recursive function:
function loadChannels() {
$.ajax({
type: "GET",
url: curURL,
dataType: "xml",
error: function(){ console.log('Error Loading Channel XML'); },
success: function(nXml) {
var noOfItems = parseInt($($(nXml).find('total_items')[0]).text(), 10);
var startIdx = parseInt($($(nXml).find('item_startidx')[0]).text(), 10);
var allItems = $(nXml).find('item');
$(allItems).each(function() {
var obj = $("<li><span id='cont-thumb'></span><span id='cont-name'></span></li>");
$("#content-scroller ul").append($(obj));
var imgURL = $($(this).find('item_image')[0]).text();
var contThumb = $(obj).children()[0];
$(contThumb).css("background-image", 'url('+imgURL+')');
var name = $($(this).find('name')[0]).text();
var contName = $(obj).children()[1];
$(contName).text(name).css('text-align', 'center');
var url = $($(this).find('link')[0]).text();
$(obj).data('item_link', url);
$(obj).bind('click', onJPContSelected);
});
if(startIdx+allItems.length < noOfItems){
var newIdx = new Number(startIdx+allItems.length);
var tokens = curURL.split("/");
tokens[tokens.length-2] = newIdx.toString(10);
curURL = "http:/";
for(var i=2; i<tokens.length; i++)
curURL = curURL + "/" + tokens[i];
loadChannels();
}
}
});
}
try to remove the recursion with an outer loop - something like that:
function loadChannels(){
var stopFlag = false;
// request the pages one after another till done
while(!stopFlag)
{
$.ajax({
type: "GET",
url: curURL,
dataType: "xml",
error: function(){
console.log('Error Loading Channel XML');
errorFlaf = true;
},
success: function(nXml) {
var noOfItems = parseInt($($(nXml).find('total_items')[0]).text(), 10);
var startIdx = parseInt($($(nXml).find('item_startidx')[0]).text(), 10);
var allItems = $(nXml).find('item');
$(allItems).each(function() {
var obj = $("<li><span id='cont-thumb'></span><span id='cont-name'></span></li>");
$("#content-scroller ul").append($(obj));
var imgURL = $($(this).find('item_image')[0]).text();
var contThumb = $(obj).children()[0];
$(contThumb).css("background-image", 'url('+imgURL+')');
var name = $($(this).find('name')[0]).text();
var contName = $(obj).children()[1];
$(contName).text(name).css('text-align', 'center');
var url = $($(this).find('link')[0]).text();
$(obj).data('item_link', url);
$(obj).bind('click', onJPContSelected);
});
if(startIdx+allItems.length < noOfItems){
var newIdx = new Number(startIdx+allItems.length);
var tokens = curURL.split("/");
tokens[tokens.length-2] = newIdx.toString(10);
curURL = "http:/";
for(var i=2; i<tokens.length; i++)
curURL = curURL + "/" + tokens[i];
// lets disable the recursion
// loadChannels();
}
else {
stopFlag = true;
}
}
});
}
}

Categories