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);
});
}