HTML multiple file upload from different folders
Asked Answered
Z

6

11

I have a form with an upload field that allows users to select multiple files. However, I need to be able to allow the user to select file 1 from folder 1, then go and select file 2 from folder 2, and so on.

Currently, when the user selects file 1 from folder 1 then hits "Open", the selection window closes (leaving the user on my form). Then if the user goes and select file 2 from folder 2 and hits the "Open" button, file 1 is removed, leaving only file 2.

Basically, the user is unable to select multiple files unless they're all in the same location. Is there a way to make file 1 stay selected after file 2 is chosen?

Zillah answered 22/7, 2014 at 13:50 Comment(2)
I'm pretty sure that this is impossible, the file selection window is controlled by the OS.Stricture
that is correct but its necesaryBiofeedback
W
7

No, you can't. This is a behaviour defined by the operating systems and may vary between them. You can't control these things precisly and you will always fear what happen.

If the amount of folders people have to choose is quite small you could offer multiple upload fields.

Whaling answered 22/7, 2014 at 13:52 Comment(0)
C
7

How about this?

The solution uses HTML, jQuery/Javascript, and PHP (for server-side handling of this data). The idea is: 1.) HTML Form: Includes one "browse" button that allows the user to select multiple files (within one directory). 2.) jQuery: The option to create a new button in the form that allows users to select multiple files (within a different directory -- or even the same one actually!), with the ability to create new buttons "infinitely". 3.) PHP: As a bonus, I put some thought into packaging the data nicely for server-side handling.

Here is what the HTML form could look like (I used a found-icon for the clickable object, but you can easily replace it with a graphic of your choosing).

<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>" enctype='multipart/form-data'>
    Select files: <br/>
    <input type='file' name='files0[]' id="files0" multiple><br/><br/><br/>
    <span style="font-size: 10pt;">Click "+" for more files
    <i id="more_files" class="general foundicon-plus" style="color: blue;cursor: pointer;"></i></span>
    <br/><br/><br/>
    <input type="submit" name="submit" value="Submit">
</form>

Here is the jQuery/Javascript to create a new "browse" button once the event is triggered (this even places it after the LAST "browse" button!):

<script type="text/javascript">
//jQuery
$(document).ready(function() {
    $(document).on('click','#more_files', function() {
        var numOfInputs = 1;
        while($('#files'+numOfInputs).length) { numOfInputs++; }//once this loop breaks, numOfInputs is greater than the # of browse buttons

        $("<input type='file' multiple/>")
            .attr("id", "files"+numOfInputs)
            .attr("name", "files"+numOfInputs+"[]")
            .insertAfter("#files"+(numOfInputs-1));

        $("<br/>").insertBefore("#files"+numOfInputs);
    });
});
</script>
<script>
    //vanilla javascript version
    var location = document.getElementById("fileBrowsers");
    var br = document.createElement("BR");
    location.appendChild(br);
    var input = document.createElement("input");
    input.type = "file";
    input.name = "files"+numOfInputs+"[]";
            input.id = "files"+numOfInputs;
            input.multiple = true;

            location.appendChild(input);
</script>

Finally, and possibly most important, how to wrap up the data on the server in a familiar format:

<?php
if(isset($_POST['submit']) && !empty($_FILES)) {
    $files = array();
    $files = $_FILES['files0'];
    //var_dump($files);//this array will match the structure of $_FILES['browser']
    //Iterate through each browser button
    $browserIterator = 1;
    while(isset($_FILES['files'.$browserIterator])) {
        //Files have same attribute structure, so grab each attribute and append data for each attribute from each file
        foreach($_FILES['files'.$browserIterator] as $attr => $values) {//get each attribute
            foreach($_FILES['files'.$browserIterator][$attr] as $fileValue) {//get each value from attribute
                $files[$attr][] = $fileValue;//append value
            }
        }
        $browserIterator++;
    }
    //Use $files like you would use $_FILES['browser'] -- It is as though all files came from one browser button!
    $fileIterator = 0;
    while($fileIterator < count($files['name'])) {
        echo $files['name'][$fileIterator]."<br/>";
        $fileIterator++;
    }
}
?>

Update Note: jQuery script and vanilla Javascript accomplish the same goal. I ran into an issue that required the vanilla version. You only need one of them.

Cynara answered 12/7, 2016 at 9:18 Comment(0)
S
2

Another solution is using old school (non-multiple) file inputs. In this case you cannot select multiple files to upload, but you can remove any file and add another. Initially there is only one file input on page, but when you select a file, it hiding and replacing by filename with delete button, and new file input appears.

var fileInput = document.getElementById('fileInput_0');
var filesList =  document.getElementById('fileList');  
var idBase = "fileInput_";
var idCount = 0;

var inputFileOnChange = function() {

    var existingLabel = this.parentNode.getElementsByTagName("LABEL")[0];
    var isLastInput = existingLabel.childNodes.length<=1;

    if(!this.files[0]) {
        if(!isLastInput) {
            this.parentNode.parentNode.removeChild(this.parentNode);
        }
        return;
    }

    var filename = this.files[0].name;

    var deleteButton = document.createElement('span');
    deleteButton.innerHTML = '&times;';
    deleteButton.onclick = function(e) {
        this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);
    }
    var filenameCont = document.createElement('span');
    filenameCont.innerHTML = filename;
    existingLabel.innerHTML = "";
    existingLabel.appendChild(filenameCont);
    existingLabel.appendChild(deleteButton);
    
    if(isLastInput) {   
        var newFileInput=document.createElement('input');
        newFileInput.type="file";
        newFileInput.name="file[]";
        newFileInput.id=idBase + (++idCount);
        newFileInput.onchange=inputFileOnChange;
        var newLabel=document.createElement('label');
        newLabel.htmlFor = newFileInput.id;
        newLabel.innerHTML = '+';
        var newDiv=document.createElement('div');
        newDiv.appendChild(newFileInput);
        newDiv.appendChild(newLabel);
        filesList.appendChild(newDiv);
    } 
}

fileInput.onchange=inputFileOnChange;
#fileList > div > label > span:last-child {
    color: red;
    display: inline-block;
    margin-left: 7px;
    cursor: pointer;
}
#fileList input[type=file] {
    display: none;
}
#fileList > div:last-child > label {
    display: inline-block;
    width: 23px;
    height: 23px;
    font: 16px/22px Tahoma;
    color: orange;
    text-align: center;
    border: 2px solid orange;
    border-radius: 50%;
}
<form enctype="multipart/form-data" method="post">
    <div id="fileList">
        <div>
            <input id="fileInput_0" type="file" name="file[]" />
            <label for="fileInput_0">+</label>      
        </div>
    </div>
</form>
Sinaloa answered 4/8, 2018 at 1:19 Comment(0)
O
0

Here is the complete Solution

<!DOCTYPE html>
<html>
<head>
  <title>Custom File Selection</title>
</head>
<body>
  <input type="file" id="customFileInput" multiple style="display: none">
  <button onclick="openCustomFileInput()">Select Files</button>
  <ul id="selectedFilesList"></ul>

  <script>
    var selectedFiles = []; // Array to store the selected files

    function openCustomFileInput() {
      var fileInput = document.getElementById('customFileInput');
      fileInput.click();
    }

    function handleCustomFileInput(event) {
      var fileList = event.target.files;
      var selectedFilesList = document.getElementById('selectedFilesList');

      for (var i = 0; i < fileList.length; i++) {
        var file = fileList[i];
        selectedFiles.push(file); // Add the newly selected file to the array

        var listItem = document.createElement('li');
        listItem.textContent = file.name;

        var deleteButton = document.createElement('button');
        deleteButton.textContent = 'Delete';
        deleteButton.addEventListener('click', createDeleteHandler(file, listItem));
        listItem.appendChild(deleteButton);

        selectedFilesList.appendChild(listItem);
      }
    }

    function createDeleteHandler(file, listItem) {
      return function() {
        var index = selectedFiles.indexOf(file);
        if (index !== -1) {
          selectedFiles.splice(index, 1); // Remove the file from the array
        }

        listItem.parentNode.removeChild(listItem); // Remove the list item from the list
      };
    }

    document.getElementById('customFileInput').addEventListener('change', handleCustomFileInput);
  </script>
</body>
</html>
Offcenter answered 22/6, 2023 at 8:32 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Mathian
B
0

Here is code that worked for me:

  SetupMultiFile(file);

    function SetupMultiFile(file) {
        var list = [];
    
        file.addEventListener('click', function () {
            list = [];
            for (var i = 0; i < file.files.length; i++) {
                list.push(file.files[i]);
            }
        });
    
        file.addEventListener('change', function () {
            if (list.length == 0) return;
    
            var oNames = {};
            var oDataTransfer = new DataTransfer();
    
            //copy new
            for (var i = 0; i < file.files.length; i++) {
                oDataTransfer.items.add(file.files[i]);
                oNames[file.files[i].name] = true;
            }
    
            //copy old
            for (var i = 0; i < list.length; i++) {
                if (oNames[list[i].name]) { } else {
                    oDataTransfer.items.add(list[i])
                }           
            }
    
            file.files = oDataTransfer.files;
        });
    }
<input type=file multiple id='file'>
Bertrambertrand answered 8/12, 2023 at 21:8 Comment(0)
A
-1

document.querySelector("input").addEventListener("change", list_files);

function list_files() {
  var files = this.files;
  for (var i = 0; i < files.length; i++) {
    console.log(files[i].name);
  }
}
<input type="file" multiple>
Aerialist answered 9/8, 2019 at 7:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.