Reputation: 244
Hi I'm trying to implement a script creating multiple file uploads preview using FileReader. This is my starting point
<input id="attachments" type="file" multiple="multiple" name="attachments">
<table id="file_info_attachments" class="table table-preview"></table>
What I want to do is to read uploaded files list, put their names and size into file_info_attachments table (one row for every file) and, the tricky part, if they're images, add in the same row a preview.
My ideal preview should look like this
<input id="attachments" type="file" multiple="multiple" name="attachments">
<table id="file_info_attachments" class="table table-preview">
<tr>
<td>No preview</td>
<td>file_1.txt</td>
<td>2000</td>
</tr>
<tr>
<td><img src="[IMAGE DATA]" /></td>
<td>file_2.png</td>
<td>2000</td>
</tr>
</table>
My parsing function scratch looks like this:
function parseFiles(files, id) {
$("#file_info_" + id).html("");
if(files.length > 0) {
for (var i = 0; i < files.length; i++) {
$("#file_info_" + id).append("<tr><td class=\"preview preview_" + i + "\">No preview</td><td>" + files[i].name + "</td><td>Size: " + files[i].size + "</td></tr>");
if(/\.(jpe?g|png|gif)$/i.test(files[i].name) && typeof (FileReader) != "undefined") {
var reader = new FileReader();
reader.onload = function(e){
//obviously I cannot do that this way due to how reader.onload works
//$("#file_info_" + id + " .preview_" + i).html("<img src=\"" + e.target.result + "\" />");
};
reader.readAsDataURL(files[i]);
}
}
}
}
And that's how I call parseFiles function:
$(document).on("change", "#attachments", function(){
var files = $(this)[0].files;
parseFiles(files, "attachments");
});
I know I can make it work just by appending info rows into reader.onload function instead of adding that right after for cycle but, since I'm handling different types of files, I'd like just to keep them ordered and just update the preview field in case they're images. How can I just make reader.onload update the inner HTML of my preview by adding the
Thanx in advance.
Upvotes: 1
Views: 1224
Reputation: 137171
Not sure if browsers will preserve the order in which user has selected multiple files Actualy I'm pretty confident it is ordered alphabetically on my FF, but to display your images in the same order as you get in the input.files
property,
simply don't use a FileReader for reading user selected Files.
Instead, you should prefer URL.createObjectURL()
method.
This method is synchronous, so you won't have to deal with different scopes, also, for user selected Files, this is just a direct pointer to the File stored in user system, i.e, memory impact is almost 0.
file.onchange = function(e) {
for (let i = 0; i < this.files.length; i++) {
let url = URL.createObjectURL(this.files[i]);
let img = new Image();
img.src = url;
document.body.appendChild(img);
// you can even free these 10bits you occupy in memory if you don't need the url anymore
img.onload = function() {
URL.revokeObjectURL(this.src);
}
console.log(this.files[i].name);
}
}
<input type="file" accept="image/*" multiple id="file">
Upvotes: 6