I want to list selected file from file input.
<div class="fileUpload myButton">
<span>Upload</span>
<input type="file" name="imageURL[]" id="imageURL" multiple="" class="file" />
</div>
<div id="file-list">
</div>
I have this code
(function () {
var filesUpload = document.getElementById("imageURL"),z
fileList = document.getElementById("file-list");
function uploadFile (file) {
var li = document.createElement("li"),
div = document.createElement("div"),
reader,
xhr,
fileInfo;
li.appendChild(div);
// Present file info and append it to the list of files
fileInfo = "<div class=\"neutral\">File: <strong>" + file.name + "</strong> with the size <strong>" + parseInt(file.size / 1024, 10) + "</strong> kb is in queue.</div>";
div.innerHTML = fileInfo;
fileList.appendChild(div);
}
function traverseFiles (files) {
if (typeof files !== "undefined") {
for (var i=0, l=files.length; i<l; i++) {
uploadFile(files[i]);
}
}
else {
fileList.innerHTML = "<div class=\"neutral\">Your browser does not support Multiple File Upload, but you can still upload your file. We recommend you to upload to a more modern browser, like Google Chrome for example.<div>";
}
}
filesUpload.addEventListener("change", function () {
traverseFiles(this.files);
}, false);
})();
But the problem is when the user selects another files it is added to the list but the old files is not uploaded when the form is submitted.
Simplified: when the user selects file1.pdf and file2.pdf
The list shows file1.pdf and file2.pdf
When he selects again another files file3.pdf and file4.pdf
the list shows file1.pdf , file2.pdf, file3.pdf and file4.pdf
But when he submit the form only file3.pdf and file4.pdf is uploaded
My question is how to remove the files which will not be uploaded from the list.
OR a way to upload all the files in the list.
Thanks in advance.
What is happening is that the input is emptied when selecting more files, hence not uploading the previously displayed files.
SOLUTION 1: To combat this you could create a new input in the change event handler, although this could get quite messy.
You would have to get all files from all the inputs on upload. You have not shown your actual upload code, so I cannot give an example in context:
filesUpload.on("change", function () {
traverseFiles(this.files); //Add initial files to list
create_new_input();
}
function create_new_input() {
var new_input = $('<input type="file" />'); //create file selector
new_input.on("change", function() {traverseFiles($(this).get(0).files);}); //
$('body').append(new_input); //Add this input to your page
}, false);
You will have to add all files that you receive in the traverseFilesto the xhr. This example uses jQuery, and I would recommend that you use it all the time!
SOLUTION 2:
Other wise you can empty the file list box on input changed:
filesUpload.addEventListener("change", function () {
document.getElementById('file-list').innerHTML = "";
traverseFiles(this.files);
}, false);
Good luck!
Your Problem is that you manipulate the value of input multiple times. The second time someone selects a file using the html file input, the originally selected files are "overwritten" from the inputs value attribute.
You could hook into your forms submit and add the files you already stored in your html.
Another way to do it would be to work with several file input elements.
So every time someone selects files and you add them to your html, hide the old file input and add a new one like this ...
adjust your html code like this:
<div class="fileUpload myButton">
<span>Upload</span>
<input type="file" class="imageUrlInput" name="imageURL[0]" id="imageURL" multiple="" class="file" />
</div>
<div id="file-list">
</div>
Adjust your Javascript like this:
function uploadFile (file) {
var li = document.createElement("li"),
div = document.createElement("div"),
reader,
xhr,
fileInfo;
li.appendChild(div);
// now here we receive the HTML input element for the files.
var currentInput = $('#imageURL');
var imageUrlInputsCount = $('.imageUrlInput').length;
// now we change the 'id' attribute of said element because id's should be unique right?
currentInput.attr('id','imageUrl_'+imageUrlInputsCount);
// now, we append a new input element with an incremented array key defined by the length of already existing input elements
currentInput.append('<input type="file" name="imageURL['+imageUrlInputsCount+']" id="imageURL" multiple="" class="file" />');
// and finally we hide the old element
currentInput.hide();
// Present file info and append it to the list of files
fileInfo = "<div class=\"neutral\">File: <strong>" + file.name + "</strong> with the size <strong>" + parseInt(file.size / 1024, 10) + "</strong> kb is in queue.</div>";
div.innerHTML = fileInfo;
fileList.appendChild(div);
}
Now make sure that in your retrieving server code (php/jsp/asp,node.js or whatever you are using) you change checking for imageURL, you iterate over imageURL since now you have several sets of imageURLs. i.e. your imageURL parameter could look like this:
imageURL = array (
0 => array(
'foo1.pdf',
'foo2.pdf',
'foo3.pdf',
),
1 => array(
'foo4.pdf',
'foo5.pdf',
'foo6.pdf',
)
3 => array(
'foo7.pdf',
'foo8.pdf',
'foo9.pdf',
)
)
Related
I am using input type='file' with multiple file and one with single file. like,
//single image
//IMAGE_TYPES is constant and defined with:define('IMAGE_TYPES',array('main','floor','bedroom1','bedroom2','bedroom3','kitchen','reception','garages','epc','other'));
#foreach(IMAGE_TYPES as $images)
#if($images!='other')
<div class="col-sm-10">
<input type="file" class="form-control" id="{{$images}}_image" name="{{$images}}_image" accept="image/*" placeholder="<span> <i class='fa fa-plus-circle'></i>Click here or drop files to upload</span>"/>
</div>
#else
//multiple
<div class="col-sm-10">
<input type="file" class="form-control" id="other_images" name="other_images[]" accept="image/*" placeholder="<span> <i class='fa fa-plus-circle'></i>Click here or drop files to upload</span>" multiple />
</div>
#endif
#endforeach
Now, I validating it with jquery like,
var image_type ='<?=json_encode(IMAGE_TYPES);?>';
image_type = JSON.parse(image_type);
var max_image_size = 2;
$.each(image_type, function( index, value ) {
if (value!='other') {
$('#'+value+'_image').bind('change', function() {
var a=(this.files[0].size);
var ValidImageTypes = ["image/jpeg", "image/png"];
if ($.inArray(this.files[0].type, ValidImageTypes) < 0) {
show_notification('error','Only .jpg/.jpeg and .png file allowed. Please select other image.');
var file = document.getElementById(value+'_image');
file.value = file.defaultValue;
return false;
}
else{
if (Math.round(a / (1024 * 1024)) > max_image_size) {
show_notification('error','Image is Greater than '+max_image_size+'MB. Please select smaller image.');
var file = document.getElementById(value+'_image');
file.value = file.defaultValue;
return false;
}
else
{
preview_main_image(value);//won't matter
}
}
});
}
else{
$('#other_images').bind('change', function() {
$('div.add_preview').remove();//won't matter
for (var i = 0; i < $("#other_images").get(0).files.length; i++) {
var a=(this.files[i].size);
var name = this.files[i].name;
var ValidImageTypes = ["image/jpeg", "image/png"];
if ($.inArray(this.files[i].type, ValidImageTypes) < 0) {
show_notification('error','Image '+name+' is Not allowed. Only .jpg/.jpeg and .png file allowed. Please select other image.');
}
else{
if (Math.round(a / (1024 * 1024)) > max_image_size) {
show_notification('error','Image '+name+' is Greater than '+max_image_size+'MB. Please select smaller image.');
}
else
{
$('#other_image_preview').append("<div class='col-md-2 p_3 add_preview'><img class='img-responsive' src='"+URL.createObjectURL(event.target.files[i])+"'></div>");//won't matter
//preview_detail_images(value);
}
}
}
});
}
});
Now, my question is when i am using single image if image is not fitting in validation then i delete it's value from input type='file' using, this code
var file = document.getElementById(value+'_image');
file.value = file.defaultValue;
return false;
But when i select multiple image and if any image is not fitting in validation then how can i remove that particular image from input type='file'.
Please help me
The file will have to come in input element for the input change handler to work. You can validate there and show only valid files in preview, ignoring the invalid ones.
You can check jQuery file uploader: https://blueimp.github.io/jQuery-File-Upload/
You can keep your input invisible over another div which is your preview and show the uploaded files in the div to give the illusion to the user that you are discarding invalid files.
The answer is simple: You can't. Value of files property of an <input type="file"> is a FileList. This one is immutable for security reasons. Also the files property is readonly and you can't construct a FileList.
The best you could do is to a) show a validation error to user and ask him to remove the file; b) ignore the file on processing (e.g. preview, uploading to server).
As #mixable already pointed out in his answer, validation should also be done on backend.
You can just ignore this file type on the server when processing the uploaded files. This is the better solution, because it is more secure. When you rely on JavaScript, it is very easy to send manipulated data to your server and upload filetypes of other images (or even scripts like js, php, ...).
Hi please check out my fiddle. I created a form which can be automatically submitted with valid files.
https://jsfiddle.net/2ah5r0bj/135/
What I did is basically:
var form = document.getElementById("myAwesomeForm");
var formDataToUpload = new FormData(form);
...
for (var i = 0; i < validFiles.length; i++) {
formDataToUpload.append("other_images[]", validFiles[i], validFiles[i].name);
}
var xhr = createCORSRequest("POST", "https://httpbin.org/post");
xhr.send(formDataToUpload);
I have various HTML elements defined in an XML file.
I cant be able to display my XML element as whole but it has multiple rows and each row consists of checkboxes, File upload option, etc.
I am using Javascript to get these elements and then using XMLHTTPRequest, sending these requests to the controller to process.
Imagine HTML elements be like below:
Row1 ---- Checkbox1_Row1 TextDescription_Row1 FileUpload_Row1
Row2 ---- Checkbox1_Row2 TextDescription_Row2 FileUpload_Row2
I can have how many ever rows as possible.
Using Javascript, I am getting all these form elements and these elements are differentiated by Row number (Row1, Row2).
I am looping through each form elements and then
for(var j=0; j< formelements.length; j+++)
{
if (formElements[j].type == "textbox")
{
Do something
}
elseif (formElements[j].type == "file")
{
var Base64String;
var ready = false;
var fileName = formElements[j].files[0].name;
var check = function () {
if (ready === true) {
array.push(Base64String);
return;
}
setTimeout(check, 1000);
}
check();
var reader = new FileReader();
reader.onloadend = function (evt) {
Base64String = evt.target.result;
ready = true;
};
reader.readAsDataURL(file);
}
}
I am using an array to push all the values corresponding to each row and the array with final value will be sent to the controller after some alterations. Here for file upload option, I am reading the file from each row and converting them into binary format and sending to the controller. This approach works fine, if there is only one row. What happens with this approach when there are multiple rows is, while looping through the form element, it check everything for the first row (say textbox) and puts into the array but when it is file type, it goes to the loop and reads the file. Reading the file takes sometime here and by the time loop goes to the next form element (which is nothing but Row2). Now Row2 form element comes into picture and say, we do not upload any file, it will be null. Now check() function gets completed and file from row1 is read completely. Since the loop is already in for Row 2 form element, this file value is getting assigned to Row2 apart from null values. So Row2 will have both null value and file value when it comes to file type but there is no value for Row1. Similarly if I have many files in multiple rows, the file value gets assigned to which ever row form element that is there in current loop based on the time read by FileReader.
I need to make sure that file value is read completely before moving on to the next form element. How to achieve this?
************************Updates**********************
The question which was referred here marking mine as duplicate has only file type coming in and hence, they can loop through the file type. For me, form elements consists of Checkbox1_Row1, TextDescription_Row1, FileUpload_Row1, Checkbox1_Row2 , TextDescription_Row2, FileUpload_Row2.
I have to make sure that FileUpload_Row1 has right value read from the file before moving on to to next form element, here Checkbox1_Row2.
evt should be event at evt.target.result. .push() event.target.result to fileList array, do stuff when fileList .length is equal to count
<!DOCTYPE html>
<html>
<head>
<script>
function myFunction() {
var files = Array.prototype.map.call(
document.querySelectorAll("[id^=myFile]")
, function(input) {
return {id:input.dataset.id, file: input.files[0]};
});
var count = files.length; // total number of files
var fileList = []; // accepted files
for (var i = 0; i < count; i++) {
var file = files[i].file;
var id = files[i].id;
var filename = files[i].file.name;
if (i >= count) {
break;
}
var reader = new FileReader();
reader.onload = (function(id, filename) {
return function(event) {
fileList.push({id, filename, file:event.target.result}); {
if (fileList.length === count) {
// do stuff with `fileList`
console.log(fileList);
}
}
}
})(id, filename);
reader.readAsDataURL(file);
}
}
</script>
</head>
<body>
<h1>Hello Plunker!</h1>
<input type="file" id="myFile_row1" data-id="A">
<input type="file" id="myFile_row2" data-id="B">
<input type="file" id="myFile_row3" data-id="C">
<button onclick="myFunction()">Try it</button>
</body>
</html>
plnkr http://plnkr.co/edit/VCGPPbWcock0PgC9wMWi?p=preview
I have the following code for multiple file input
<form action="" enctype = "multipart/form-data" method="post" name="login">
<input type = "file" name = "photo[]" id = "files" multiple onchange = "handleFileSelect(this.files)"/><br/>
<div id="selectedFiles"></div>
<input type="submit" value="Sign In">
</form>
The javascript equivalent function is.
selDiv = document.querySelector("#selectedFiles");
function handleFileSelect(e) {
if(!this.files) return;
selDiv.innerHTML = "";
var files = e;
for(var i=0; i<files.length; i++) {
var f = files[i];
selDiv.innerHTML += f.name + "<br/>";
}
}
What I am getting is upon uploading the second file. The FileList gets overwritten and instead of having 2 files, second file is present in the FileList. Here FileList is passed by this.files.
Also upon passing to the server only second image is passed. I have googled throughly but could not find answer. I would appreciate if anyone could help.
...multiple file input ... The FileList gets overwritten...
Actually that's how the HTML file input with the multiple attribute works—the user must select all the files they want to upload at once, using shift or control click. If the user operates the same file input upload process a second time anything selected prior is discarded and only the most recent selections remain in the FileList.
But isn't there any way for the user upload file multiple times.
To let your site users use an HTML file input element multiple times and keep all the previous selections, you'll need to write to hidden form elements the file (base64 data) received each time the file element is used.
For example:
<form action="process.php" method="post" name="uploadform" enctype="multipart/form-data">
// other form elements if needed
<input type="submit">
</form>
<!-- outside the form, you don't want to upload this one -->
<input type="file" id="upfiles" name="upfiles">
<script>
document.getElementById('upfiles').addEventListener('change', handle_files, false);
function handle_files(evt) {
var ff = document.forms['uploadform'];
var files = evt.target.files;
for ( var i = 0, file; file = files[i]; i++ ) {
var reader = new FileReader();
reader.onload = (function(file) {
return function (ufile) {
var upp = document.createElement('input');
upp['type'] = 'hidden';
upp['name'] = +new Date + '_upfile_' + file.name.replace(/(\[|\]|&|~|!|\(|\)|#|\|\/)/ig, '');
upp.value = ufile.target.result;
ff.appendChild(upp);
}
}(file));
reader.readAsDataURL(file);
}
}
</script>
Next, you need to write a script to run on the server to process the hidden base64 fields. If using PHP you can:
<?php
$path = 'path/to/file/directory/';
// this is either:
// - the absolute path, which is from server root
// to the files directory, or
// - the relative path, which is from the directory
// the PHP script is in to the files directory
foreach ( $_POST as $key => $value ) { // loop over posted form vars
if ( strpos($key, '_upfile_') ) { // find the file upload vars
$value = str_replace(' ', '+', $value); // url encode
file_put_contents($path.$key, base64_decode($value));
// convert data to file in files directory with upload name ($key)
}
}
?>
I ran into the same problem. Thanks for the question and answer. I managed to add several files by adding to the DOM input type file and delegating the click to the detached element :
<form method="POST" enctype="multipart/form-data" action="/echo/html">
<button class="add">
Add File
</button>
<ul class="list">
</ul>
<button>
Send Form
</button>
</form>
With the javascript :
$('form button.add').click(function(e) {
e.preventDefault();
var nb_attachments = $('form input').length;
var $input = $('<input type="file" name=attachment-' + nb_attachments + '>');
$input.on('change', function(evt) {
var f = evt.target.files[0];
$('form').append($(this));
$('ul.list').append('<li class="item">'+f.name+'('+f.size+')</li>');
});
$input.hide();
$input.trigger('click');
});
It is working with Edge, Chrome 50 and firefox 45, but I don't know the compatibility with older versions or other browsers.
See the this fiddle.
Im uploading multiple pdfs at same time, and Im trying to find a method to give a a custom title for each uploaded pdf.
So I thought at first using php, I store a variable to count pdfs that the user selected
$countPdfs = count($_FILES['pdfs']['tmp_name']);
And then in my form, I have some php where I show a text input to write a title for each pdf that I upload.
<div class="galerry">
<div class="label">
<span class="field">Pdfs:</span>
<input type="file" name="pdfs[]" class="j_gallerypdf" multiple="multiple" accept="application/pdf" />
<div class="j_gfalsepdf">Select many pdfs</div>
<img src="img/upload.png" class="j_gsendpdf"/>
</div>
<?php
if(isset($countPdfs )){
for($i=1;$i<=$countPdfs ;$i++){
echo '<div class="label">';
echo '<span class="field">Pdf Title:</span>';
echo '<input type="text" name="title" />';
echo '</div>';
}
}
?>
</div>
And so If I select 5 pds it shows me 5 text inputs, it is working fine.
But I need to send my form and only after send form my inputs appear.
Do you know how can I do this using jQuery? After I select my pdfs in my input file, show the same number of input texts that my number of selected pdfs?
Im already using this jQuery function below to show in my input the number of pdfs that user select:
$('.j_gsendpdf').click(function(){
$('.j_gallerypdf').click().change(function(){
var numFiles = $(this)[0].files.length;
$('.j_gfalsepdf').animate({width:'400'}, 500, function(){
$(this).html('You selected'+ numFiles +'</strong> files.');
});
});
});
But do you know how can I use this numFiles also to open a number of input texts icual to my numFiles variable?
One approach is the following:
// binding a change event-handler to the file-input(s):
$('input[type="file"]').on('change', function(){
// finding the closest '.gallery' element, then finding
// its descendant 'fieldset' element, removing the 'empty' class
// (that it has on page-load to hide it while empty):
var fieldset = $(this).closest('.gallery').find('fieldset').removeClass('empty'),
// we're using the fileList so we're caching it, the other two are
// used later (in the for loop):
files = this.files, curFile, label;
for (var i = 0, len = files.length; i < len; i++){
// caching the 'current file' in the prepared variable:
curFile = files[i];
// creating a label element, keeping a reference in the
// prepared variable:
label = $('<label />', {
'html' : 'Change the name of <span class="filename">' + curFile.name + '</span>?'
// appending the created 'label' to the fieldset:
}).appendTo(fieldset);
// creating an 'input' element:
$('<input />', {
'type' : 'text',
// the current value is the current file-name:
'value' : files[i].name
// appending that to the created/appended 'label' element:
}).appendTo(label);
}
});
JS Fiddle demo.
The above approach relies on the presence of a fieldset identifying where the createdinput elements should be appended, so I've changed your HTML to the following:
<form action="#" method="post">
<div class="gallery">
<div class="label"> <span class="field">Pdfs:</span>
<input type="file" name="pdfs[]" class="j_gallerypdf" multiple="multiple" accept="application/pdf" />
<div class="j_gfalsepdf">Select many pdfs</div>
<fieldset class="empty">
<legend>Titles</legend>
</fieldset>
</div>
</div>
</form>
This approach is, however, moderately naive: if you reselect new files from the file input it will create, and append, new <label> and <input> elements. This could be partially countered (assuming it's not an inconvenience to you, or your users, by removing previously-created elements), using empty(): JS Fiddle demo.
References:
appendTo().
Attribute-equals ([attribute="value"]) selector.
closest().
empty().
find().
on().
I did it this way.
$('.j_gallerypdf').click().change(function(){
var allFiles = this.files;
var numFiles = this.files.length;
$('.j_gfalsepdf').animate({width:'400'}, 500, function(){
$(this).html('You selected'+ numFiles +'</strong> files.');
for(var i = 0; i<numFiles; i++) {
var file = allFiles[i], name = file.name;
$(this).append('<input type="text" name="title[]" value="'+name+'"/>');
}
});
});
I'm having a problem sending the images have a text area field for the client to send a description of the photo, and when he sent to the database sends as if all had the same description that was being inserted only one description,
I'm using the library DROPZONE.JS http://dropzonejs.com/
Follow my code .. Help me please.
Dropzone.options.upload = {
thumbnailWidth: 246,
thumbnailHeight: 173,
enqueueForUpload:false,
paramName: "userfile",
sending: function(file, xhr, formData) {
formData.append("titulo", $("#titulo").val());
formData.append("evento", <?php echo $this->uri->segment(4); ?>);
formData.append("capa", $("#cap").val());
}
};
function upload() {
var dz = Dropzone.forElement("#upload");
for (var i = 0; i < dz.files.length; i++) {
dz.filesQueue.push(dz.files[i]);
}
dz.processQueue();
}
As stated there can only be one DOM element having an id in the whole document or you will have issues. This can be solved on the fly by adding the file name to the id of your text box field.
Add code for your text box in the previewTemplate
previewTemplate: "<div class=\"dz-preview dz-file-preview\"> ...
<input type=\"text\" class=\"titulo\" data-dz-titulo >
...
data-dz-errormessage></span></div>\n</div>"
When the previewTemplate is rendered by the addedfile function create an id called titulo + file.name to give your element a unique id. This can be done by adding a line of code in the addedfile function.
addedfile: function(file) {
file.previewElement = Dropzone.createElement(this.options.previewTemplate);
...
file.previewElement.querySelector("[data-dz-titulo]").id = "titulo" + file.name;
...
file.previewElement.querySelector("[data-dz-size]").innerHTML = this.filesize(file.size);
},
Now you will also have to use the file name to get the matching titulo in the sending function.
sending: function(file, xhr, formData) {
var filetitulo = document.getElementById('titulo' +file.name).value;
formData.append("titulo", filetitulo);
});
When you use $("#titulo") you refer to the input / textarea having the id of titulo.
For example <input type="text" id="titulo">.
There can only be one DOM element having an id in the whole document.
Change your element to <input type="text" class="titulo"> then you use something like $(".titulo")[0], $(".titulo")[1] to select the fields.