I made a file uploader that handles images, but it doesn't work well with files.
For example: if I upload 3 xlsx/word or any files, these will have the same name for each.
My code is here:
<form>
<input id="files" type="file" multiple="multiple">
<div id="result"></div>
</form>
function handleFileSelect(event) {
if (window.File && window.FileList && window.FileReader) {
var files = Array.from(event.target.files);
var output = document.getElementById("result");
output.innerHTML = '';
console.log(files);
for (var i = 0; i < files.length; i++) {
var file = files[i];
if(file.type.match('.php')){
alert('ERROR');
continue;
}
var picReader = new FileReader();
picReader.addEventListener("load", function (event) {
var picFile = event.target;
var div = document.createElement("div");
div.className = "col-6 col-sm-4 p-1";
if (file.type.match('image')) {
div.innerHTML = "<img src='" + picFile.result + "'" + "title='" + file.name + "'/>";
}else{
div.innerHTML = "<div class='upload-thumb'>" + file.name + "</div>";
}
output.insertBefore(div, null);
});
picReader.readAsDataURL(file);
}
} else {
console.log("Your browser does not support File API");
}
}
Link:
https://jsfiddle.net/laszlooo/7c1Lv5x2/
Thank You!
Problem you have is you have the infamous for loop bug. Where the reference to i updates as your loop executes. You can either use let instead of var or break out the part you read the file into a function so you do not have the issue.
function readFile(file, output) {
var picReader = new FileReader();
picReader.addEventListener("load", function(event) {
var picFile = event.target;
var div = document.createElement("div");
div.className = "col-6 col-sm-4 p-1";
if (file.type.match('image')) {
div.innerHTML = "<img src='" + picFile.result + "'" + "title='" + file.name + "'/>";
} else {
div.innerHTML = "<div class='upload-thumb'>" + file.name + "</div>";
}
output.insertBefore(div, null);
});
picReader.readAsDataURL(file);
}
function handleFileSelect(event) {
if (window.File && window.FileList && window.FileReader) {
var files = Array.from(event.target.files);
var output = document.getElementById("result");
output.innerHTML = '';
console.log(files);
for (var i = 0; i < files.length; i++) { // <-- where the problem begins
var file = files[i]; // <-- this is your problem with the reference
if (file.type.match('.php')) {
alert('ERROR');
continue;
}
readFile(file, output) // <-- using a function gets around the reference issue
}
} else {
console.log("Your browser does not support File API");
}
}
document.querySelector("input").addEventListener("change", handleFileSelect)
<form>
<input id="files" type="file" multiple="multiple">
<div id="result"></div>
</form>
Related
I have this code that allows you to upload multiple images and preview it. I also want to get the images name and their size. Its only works while you upload only one image. If you upload more than one, the image properties will be the same for each images. (They'll get the last ones infos.)
I think the problem is in the picReader function, because it bugs with the for loop. Any idea how to sole it?
What I want: I want to get the file.name which is the name of the image (e.x: example.jpg) and the file.size which is the size of the image (e.x: 181135) for each images one by one with their own infos. But now, it will display the same infos for each images (= It will show the last image's infos for the others too).
function handleFileSelect() {
if (window.File && window.FileList && window.FileReader) {
document.getElementById('result').textContent = '';
var files = event.target.files; //FileList object
var output = document.getElementById("result");
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (!file.type.match('image')) continue;
var picReader = new FileReader();
picReader.addEventListener("load", function (event) {
var picFile = event.target;
var div = document.createElement("div");
div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" + "title='" + picFile.name + "'/>";
console.log(file.name+'::'+file.size);
output.insertBefore(div, null);
});
picReader.readAsDataURL(file);
}
} else {
console.log("Your browser does not support File API");
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
body {
font-family:'Segoe UI';
font-size: 12pt;
}
header h1 {
font-size:12pt;
color: #fff;
background-color: #F39C12;
padding: 20px;
}
article {
width: 80%;
margin:auto;
margin-top:10px;
}
.thumbnail {
height: 100px;
margin: 10px;
}
output {
display: flex;
}
<article>
<label for="files">Select multiple files:</label>
<input id="files" type="file" multiple="multiple" />
<output id="result" />
</article>
The problem is that i, inside all anonymous functions which you pass as the load event listener, has the same variable outside of the function which makes the file variable to be same for all iterations as well.
You have 3 options here:
ES6:
If you are using ES6, you can use let instead of var. Each iteration of the loop with a let index, has a new variable i:
for (let i = 0; i < files.length; i++) {
let file = files[i];
if (!file.type.match('image')) continue;
var picReader = new FileReader();
picReader.addEventListener("load", function (event) {
var picFile = event.target;
var div = document.createElement("div");
div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" + "title='" + picFile.name + "'/>";
console.log(file.name+'::'+file.size);
output.insertBefore(div, null);
});
picReader.readAsDataURL(file);
}
forEach method:
files.forEach(function(file) {
if (!file.type.match('image')) continue;
var picReader = new FileReader();
picReader.addEventListener("load", function (event) {
var picFile = event.target;
var div = document.createElement("div");
div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" + "title='" + picFile.name + "'/>";
console.log(file.name+'::'+file.size);
output.insertBefore(div, null);
});
picReader.readAsDataURL(file);
})
A function that creates another function: With this solution, you would bind the variable inside each function to a value that does not change:
for (let i = 0; i < files.length; i++) {
let file = files[i];
if (!file.type.match('image')) continue;
var picReader = new FileReader();
picReader.addEventListener("load", createFunc(i, files));
picReader.readAsDataURL(file);
}
function createfunc(i, files) {
return function(event) {
var file = files[i];
var picFile = event.target;
var div = document.createElement("div");
div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" + "title='" + picFile.name + "'/>";
console.log(file.name+'::'+file.size);
output.insertBefore(div, null);
});
}
I have a function that is part of a fileupload, however when i try to validate the files through an array, wether i use an "accepted" file or a "wrong" file, i get the same end result which is the alert message on the return false statement of the code.
can someone spot an error here ? there are no syntax errors in the function.
handleFiles = function (files,e){
var rand = Math.floor((Math.random()*100000)+3);
for(var i=0, file; file = files[i]; i++) {
var fileType = new Array("psd","ai","eps","svg","png","doc","docx","jpg","jpeg","pptx","ppt","gif");
var file_extension = file.name.split('.').pop().toLowerCase();
if (parseInt(file.size / 1024) > 204800) {
alert("Filen er \""+file.name+"\" for stor");
return false;
}
if (fileType[i]==file_extension)
{
var src = '/printuploads/upload.png'
var template = '<div class="eachImage" id="'+rand+'">';
template += '<span class="preview" id="'+rand+'"><img src="'+src+'"><span class="overlay"><span class="updone"></span></span>';
template += '</span>'
template += '<div class="progress" id="'+rand+'"><span></span></div>';
if($("#dropbox .eachImage").html() == null)
$("#dropbox").html(template);
else
$("#dropbox").append(template);
upload(file,rand);
return true;
}
alert("Forkert filformat");
return false;
}
};
Your validation to check if the file extension is supported is incorrect:
fileType[i]==file_extension
Here, i is the index of file, not the extension. So every file extension is being compared with "psd".
Instead it should be checking if the extension is available in the array file_extension. You can do that using Array#some method:
fileType.some(t => t == file_extension)
Or, you can simply check that the extension belongs to the array using indexOf:
fileType.indexOf(file_extension) >= 0
Here's a working snippet, you can check the logged value in the console:
var handleFiles = function(files, e) {
var rand = Math.floor((Math.random() * 100000) + 3);
for (var i = 0, file; file = files[i]; i++) {
var fileType = new Array("psd", "ai", "eps", "svg", "png", "doc", "docx", "jpg", "jpeg", "pptx", "ppt", "gif");
var file_extension = file.name.split('.').pop().toLowerCase();
if (parseInt(file.size / 1024) > 204800) {
alert("Filen er \"" + file.name + "\" for stor");
return false;
}
if (fileType.some(t => t == file_extension)) {
console.log("Extension matches");
var src = '/printuploads/upload.png'
var template = '<div class="eachImage" id="' + rand + '">';
template += '<span class="preview" id="' + rand + '"><img src="' + src + '"><span class="overlay"><span class="updone"></span></span>';
template += '</span>'
template += '<div class="progress" id="' + rand + '"><span></span></div>';
if ($("#dropbox .eachImage").html() == null)
$("#dropbox").html(template);
else
$("#dropbox").append(template);
upload(file, rand);
return true;
}
alert("Forkert filformat");
return false;
}
};
function upload() {};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type ="file" onchange="handleFiles(this.files, event);">
I'm trying to add preview and delete option before uploading multiple images, this is what I found:
$(document).ready(function() {
if (window.File && window.FileList && window.FileReader) {
$("#files").on("change", function(e) {
var files = e.target.files,
filesLength = files.length;
for (var i = 0; i < filesLength; i++) {
var f = files[i]
var fileReader = new FileReader();
fileReader.onload = (function(e) {
var file = e.target;
$("<span class=\"pip\">" +
"<img class=\"imageThumb\" src=\"" + e.target.result + "\" title=\"" + file.name + "\"/>" +
"<br/><span class=\"remove\">Remove image</span>" +
"</span>").insertAfter("#files");
$(".remove").click(function(){
$(this).parent(".pip").remove();
});
});
fileReader.readAsDataURL(f);
}
});
} else {
alert("Your browser doesn't support to File API")
}
});
But while uploading all images are getting uploaded, how to resolve this? I'm using php.
Ok, i'm create example that solved your problem:
Your HTML
<form method="post" id="sendForm">
<input type="file" id="files" multiple>
<input type="submit">
</form>
Your JS
$(document).ready(function() {
if (window.File && window.FileList && window.FileReader) {
// Array which stores all selected images
var sendData = [];
$("#files").on("change", function(e) {
var files = e.target.files,
filesLength = files.length;
for (var i = 0; i < filesLength; i++) {
var f = files[i]
var fileReader = new FileReader();
fileReader.onload = (function(e) {
var file = e.target;
$("<span class=\"pip\">" +
"<img class=\"imageThumb\" src=\"" + e.target.result + "\" title=\"" + file.name + "\"/>" +
"<br/><span class=\"remove\">Remove image</span>" +
"</span>").insertAfter("#files");
// Add all images to array
sendData.push({file: file, url: e.target.result});
$(".remove").click(function() {
var self = $(this).parent().children();
sendData.map(function(value, currentIndex, data) {
// Remove only image which removed from preview
if (self[0].currentSrc === value.url) {
sendData.splice(currentIndex, 1);
}
});
$(this).parent().remove();
});
$("#sendForm").submit(function(e) {
// Finally post all data to your PHP url that
$.post("your/php/url", sendData);
});
});
fileReader.readAsDataURL(f);
}
});
} else {
alert("Your browser doesn't support to File API")
}
});
How do get the name and size OF images? (Javascript) After stored in array Using FileReader object ?
In the example required size and the name of the image files only .
Thank you so much
$(document).ready(function() {
var storedFiles = [];
var srcc = "";
$('#file_input').on('change', function(e) {
storedFiles = [];
for (var i = 0; i < $(this).get(0).files.length; ++i) {
storedFiles.push($(this).get(0).files[i]);
}
});
function readFile(file, callback) {
var reader = new FileReader();
reader.onload = callback;
reader.readAsDataURL(file);
}
$(document).on('click', '#btn', function(e) {
$("#div_upload").empty();
var fLen = storedFiles.length;
$("#spaneaddfile").html(" count: " + storedFiles.length);
for (var i = 0; i < fLen; i++) {
var filnameonarry = storedFiles[i].name;
var filsizeonarry = Math.round((Math.abs(parseInt(storedFiles[i].size)) * 0.000000954) * 1000) / 1000;
filnameonarry = filnameonarry.toString().trim();
filnameonarry = filnameonarry.toLowerCase();
var chkename2 = parseInt(filnameonarry.length);
var chkename3 = parseInt(filnameonarry.length - 4);
var chkename4 = filnameonarry.substring(chkename3);
if (chkename4 == '.png' || chkename4 == '.gif' || chkename4 == '.jpg' || chkename4 == '.bmp' || chkename4 == 'jpeg') {
if (window.File && window.FileReader && window.FileList && window.Blob) {
readFile(storedFiles[i], function(e) {
var html = "<div><img class='selFile' src=\"" + e.target.result + "\" data-file='" + "name" + "' title='Click to remove'>" + "get name and size" + "<br clear=\"left\"/></div>";
$("#div_upload").append(html);
});
} else {
srcc = '../background_site/close.png';
handleFileSelect3(storedFiles[i], i);
}
} else if (chkename4 == '.zip') {
srcc = '../background_site/zip.png';
handleFileSelect3(storedFiles[i], i);
} else if (chkename4 == '.rar') {
srcc = '../background_site/rar.png';
handleFileSelect3(storedFiles[i], i);
} else if (chkename4 == '.pdf') {
srcc = '../background_site/pdf.png';
handleFileSelect3(storedFiles[i], i);
} else {
srcc = '../background_site/wring.png';
handleFileSelect3(storedFiles[i], i);
}
};
});
function handleFileSelect3(evt, nmber) {
var f = evt;
var i = nmber;
var filnameonarry2 = f.name;
var filsizeonarry2 = Math.round((Math.abs(parseInt(f.size)) * 0.000000954) * 1000) / 1000;
var html = "<div> <img class='selFile' id='img_" + i + "' src='" + srcc + "' alt=''> " + filnameonarry2 + " " + filsizeonarry2 + "<br clear=\"left\"/></div>";
$("#div_upload").append(html);
}
});
.selFile {
width: 200px;
height: 200px;
float: left;
margin-bottom: 10px;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<input id="btn" name="btn" type="button" value="get view">
<input type="file" id="file_input" name="files[]" multiple />
<div id="div_upload"></div>
<div id="spaneaddfile" class="foo"></div>
I'm using a multiple file input and then a for loop to iterate through the files using FileReader. JSfiddle here: https://jsfiddle.net/zLq8rsos/. It shows filename en contents correctly, but I don't understand why the counting doesn't work. If I choose one file, it's numbered '1' (why not 0?). If I choose two files, they're both counted '2'. What am I doing wrong?
function showDetails(file, content, n) {
var start = content.substring(0, 9);
var message = "File " + n + " is " + file.name + " and starts with " + start + " .<br>";
$('#results').append(message);
}
$(document).ready(function() {
$('#files').on('change', function(evt) {
var files = evt.target.files;
if (files) {
$('#results').text("");
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
var content = e.target.result;
showDetails(theFile, content, i);
};
})(f);
reader.readAsText(f, "UTF-8");
}
} else {
console.log("Failed to load file(s)");
};
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="files" name="files[]" multiple>
<div id="results">
</div>
Use closures Modify IIFE
function showDetails(file, content, n) {
var start = content.substring(0, 9);
var message = "File " + n + " is " + file.name + " and starts with " + start + " .<br>";
$('#results').append(message);
}
$(document).ready(function() {
$('#files').on('change', function(evt) {
var files = evt.target.files;
if (files) {
$('#results').text("");
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.onload = (function(theFile,count) {
return function(e) {
var content = e.target.result;
showDetails(theFile, content, count);
};
})(f,i+1);
reader.readAsText(f, "UTF-8");
}
} else {
console.log("Failed to load file(s)");
};
});
});
Problem Statement - In for loop when you are trying to access the value of i, it has already completed the iterations and hence the value because 1 for 1 file and 2 for 2 files.
You can update your for loop to
for (var i = 0, f; f = files[i]; i++) {
(function(i){ // Added
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
var content = e.target.result;
showDetails(theFile, content, i);
};
})(f);
reader.readAsText(f, "UTF-8");
})(i+1);
}
For reference - https://jsfiddle.net/zLq8rsos/1/
JSFIDDLE
All you need is to update the count through loop each time
function showDetails(file, content, n) {
var start = content.substring(0, 9);
var message = "File " + n + " is " + file.name + " and starts with " + start + " .<br>";
$('#results').append(message);
}
$(document).ready(function() {
$('#files').on('change', function(evt) {
var files = evt.target.files;
if (files) {
$('#results').text("");
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
var x=1;
reader.onload = (function(theFile) {
return function(e) {
var content = e.target.result;
showDetails(theFile, content, x);
x++;
};
})(f);
reader.readAsText(f, "UTF-8");
}
} else {
console.log("Failed to load file(s)");
};
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="files" name="files[]" multiple>
<div id="results">
</div>
Use jquery each, the index of the file start with 0
function showDetails(file, content, n) {
var start = content.substring(0, 9);
var message = "File " + n + " is " + file.name + " and starts with " + start + " .<br>";
$('#results').append(message);
}
$(document).ready(function() {
$('#files').on('change', function(evt) {
var files = evt.target.files;
if (files) {
$('#results').text("");
$.each(files, function(i, f){
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
var content = e.target.result;
showDetails(theFile, content, i);
};
})(f);
reader.readAsText(f, "UTF-8");
});
} else {
console.log("Failed to load file(s)");
};
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="files" name="files[]" multiple>
<div id="results">
</div>