multiple file input html not working

12,675

Solution 1

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.

Solution 2

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

?>
Share:
12,675
Ritesh Jung Thapa
Author by

Ritesh Jung Thapa

Updated on August 25, 2022

Comments

  • Ritesh Jung Thapa
    Ritesh Jung Thapa over 1 year

    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.