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")
}
});
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);
});
}
Any help is greatly appreciated! I've spent so long searching but I haven't found a solution or a problem like mine...
I'm writing an Electron application, and as part of it, there is a section for the users to drag and drop files. I'm then taking that file and uploading it to AWS S3.
The first time I drag and drop it goes into my function but no request is sent out to AWS S3, I then drag and drop again and it sends out the expected request and saves the file however it's the first requests information (name, path & body), and from then on when I drag and drop the file it send outs the request every time but always with the previous request's info. It's like its one sequence behind....
This is the s3 code:
function submitNewFileS3(file, filepath) {
const AWS = require('aws-sdk');
AWS.config = new AWS.Config({
accessKeyId: localStorage.getItem("accessKeyId"),
secretAccessKey: localStorage.getItem("secretAccessKey"),
region: 'eu-west-2'
});
var upload = new AWS.S3.ManagedUpload({
params: {
Bucket: 'sampe-bucket',
Key: filepath, // File name you want to save as in S3
Body: file
}
});
return upload.promise();
}
How I call the function:
var reader = new FileReader();
reader.onload = function (e2) {
// finished reading file data.
finishUploading(e2.target.result);
}
function finishUploading(url) {
// strip off the data: url prefix to get just the base64-encoded bytes
var data;
if (url.indexOf('data:image') > -1) {
data = url.replace(/^data:image\/\w+;base64,/, "");
} else if (url.indexOf('data:application') > -1) {
data = url.replace(/^data:application\/\w+;base64,/, "");
}
//only firing after sencon upload
var buf = Buffer.from(data, 'base64');
var filePathS3 = directory + (fileName).replace(/\-/g, "_").replace(/ /g, "_");
submitNewFileS3(buf, filePathS3).then(function (response) {
console.log(response);
}).catch(function (response) {
console.log(response);
});
}
reader.readAsDataURL(f); // start reading the file data.
Does anyone have any suggestions - I'm going out of my mind...I've tried so many tutorials and solutions and they all work...on the second call...
I've double checked all the required data is ready before making the request.
Many thanks in advance!
EDIT - more of what's going on in my main before sending my file to be uploaded:
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
var directory;
if (e.target.id == 'drop_zone_overview') {
//placed in general area, check which folders are showing to get dir
console.log(e);
//get whats visible
var whatPath;
$(".icon").each(function () {
if (this.style.display != 'none') {
whatPath = this.id;
}
});
//pick one and check what root we're in
var pathArray = whatPath.split('-');
console.log(pathArray);
} else if (e.target.id == 'drop_zone_individual') {
//placed on top of folder, check dir
directory = (e.target).getAttribute('data-targetfolder');
console.log(directory);
}
var files = e.dataTransfer.files,
folder;
for (var i = 0, f; f = files[i]; i++) { // iterate in the files dropped
if (!f.type && f.size % 4096 == 0) {
// The file is a folder
folder = true;
} else {
// The file is not a folder
folder = false;
}
const fs = require('fs');
console.log(f);
var fileName = f.name;
var reader = new FileReader();
reader.onload = function (e2) {
// finished reading file data.
finishUploading(e2.target.result);
}
function finishUploading(url) {
// strip off the data: url prefix to get just the base64-encoded bytes
var data;
if (url.indexOf('data:image') > -1) {
data = url.replace(/^data:image\/\w+;base64,/, "");
} else if (url.indexOf('data:application') > -1) {
data = url.replace(/^data:application\/\w+;base64,/, "");
}
var buf = Buffer.from(data, 'base64');
var filePathS3 = directory + (fileName).replace(/\-/g, "_").replace(/ /g, "_");
submitNewFileS3(buf, filePathS3).then(function (response) {
console.log(response);
}).catch(function (response) {
console.log(response);
});
}
reader.readAsDataURL(f); // start reading the file data.
uploadedFiles.push(f);
}
uploadedFiles.forEach(function (file) {
var pathKey = directory + (file.name).replace(/\-/g, "_");
pathKey = pathKey.replace(/ /g, "_").replace(/\//g, '-').replace(/\./g, '__');
if ($('#' + pathKey).length) {
//filename already exists in directory
alert(file.name + ' already exists in folder ' + directory);
} else {
var displayDiv;
if (file.type == 'image/png') {
//image
//add to directory
displayDiv = '<img id="' + pathKey + '" class="fileInfo thumb file-type file-type-img" src="' + URL.createObjectURL(file) + '" ondblclick="preview_image(this)"/>'
} else if (file.type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
//xlsx doc
displayDiv = '<div id="' + pathKey + '" class="fileInfo thumb file-type file-type-xlsx" data-downloadLink="' + URL.createObjectURL(file) + '" ></div>';
} else if (file.type == 'application/pdf') {
//pdf doc
displayDiv = '<div id="' + pathKey + '" class="fileInfo thumb file-type file-type-pdf" data-downloadLink="' + URL.createObjectURL(file) + '" ></div>';
} else if (file.type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
//word doc
displayDiv = '<div id="' + pathKey + '" class="fileInfo thumb file-type file-type-docx" data-downloadLink="' + URL.createObjectURL(file) + '" </div>';
console.log('its a doc');
} else if (file.type == 'application/x-zip-compressed') {
//zip file doc
displayDiv = '<div id="' + pathKey + '" class="fileInfo thumb file-type file-type-zip" data-downloadLink="' + URL.createObjectURL(file) + '" </div>';
} else if (file.type == '') {
//folder
console.log('what typep is this~~~~~ ' + file.type);
file.name = file.name + '/';
}
//save to folder array
if (file.type == 'application/x-zip-compressed' || file.type == '') {
var htmlTemplate = [
getHtml([
'<li id=' + pathKey.replace(/ /g, "_").replace(/\//g, '-').replace(/\./g, '__') + ' class="icon folderItems fileInfo thumb" data-downloadLink="directory_' + pathKey + '" ondblclick="viewAlbum(this.id)" style="display:none">',
'<i id="drop_zone_individual" data-targetFolder="' + pathKey + '" class="folders fas fa-folder" style="font-size: 115px; color: rgb(13, 36, 60); cursor: pointer;"></i>',
'<div class="folderLabel" style="text-align:center">' + file.name + '</div>',
'</li>'
])
];
folders.push({
Key: directory + (file.name).replace(/\-/g, "_").replace(/ /g, "_"),
LastModified: file.lastModifiedDate,
Size: file.size,
});
} else {
//append to ui file list
var htmlTemplate = [
getHtml([
'<li id=' + pathKey + ' class="icon downloadableItem" style="display:none">',
'<span>',
'<div style="text-align:center">',
displayDiv,
'</div>',
'<div style="text-align:center">',
'<span>',
file.name,
'</span>',
'</div>',
'</span>',
'</li>'
])
];
//save to folder list
folders.push({
Key: directory + (file.name).replace(/\-/g, "_").replace(/ /g, "_"),
LastModified: file.lastModifiedDate,
Size: file.size,
signedUrl: URL.createObjectURL(file)
});
}
localStorage.setItem("s3Objects", JSON.stringify(folders));
$('#photoAlbumViewerList').append(htmlTemplate);
console.log(folders);
$("#" + pathKey).click(function (e) {
getAlbumInfo(this.id);
if (e.shiftKey) {
if ($(this).hasClass('thumb')) {
$(this).removeClass('thumb').addClass('thumbChecked');
$(this).css("border", "2px solid #c32032");
// $(this).attr("data-downloadLink");
links.push($(this).attr("data-downloadLink"));
if (links.length != 0) {
$('.download').css("display", "block");
}
} else if ($(this).hasClass('thumbChecked')) {
$(this).removeClass('thumbChecked').addClass('thumb');
$(this).css("border", "2px solid white");
var itemtoRemove = $(this).attr('src');
links.splice($.inArray(itemtoRemove, links), 1);
console.log(links);
if (links.length == 0) {
$('.download').css("display", "none");
}
}
}
});
}
});
uploadedFiles = [];
e.target.classList.remove('drop_zone_hovered');
$('#drop_zone_text').hide();
}
As an FYI - the issue lied where I reinitialised AWS and S3 variables, it wasn't needed as I set it at the start of launch and reinitialising it slowed it all down while it remade the connection!
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>
I have a html form which is used for uploading file. I can preview images and have delete option from preview itself. However, it isn't deleted from image list which used for uploading the image into server. Please help me to delete the selected image from list
Javascript code:
$(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")
}
});
Change the remove action to this, this will remove all the files
$(".remove").click(function(){
$(this).parent(".pip").remove()
$("#files").val('') // this is new
})
you can't remove only one file as e.target.files is read-only.
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>