1

I am building a BackboneJS/Marionette App and currently trying to allow users to upload multiple files.

This works when they select multiple files at the same time but I would like to have the functionality to allow them to select 1 file and then click the input again and add to the original FileList Object if possible.

Or I would like to find a way to allow my save function to grab the files from multiple inputs if need be.

I am open to any and all suggestions

This is the HTML5 File API code I am using and I am using the jquery/js offered by the MDN HTML5 File API guide

<input id="uploads" name="uploads" type="file" class="file uploads file1" multiple style="display: none"/>
<a href="#" id="fileSelect">Select File 1</a><br>
LoganRx
  • 362
  • 2
  • 13

1 Answers1

1

A FileList object from an HTMLInputElement (which is the underlying object that will hold the Files in your input.files) can only be modified in order to clear it completely (with input.value = null).

There are now ways to actually circumvent this, introduced by the DataTransfer constructor, but as of today, only Chrome and latest Firefox do support this constructor.

So the easiest in this case, is to not rely on the default UI, and instead move all your Files to a conventional Array, that you will be able to edit as you wish.

Here is one messy way, but it may give you a good starting point :
It does add an Array to your input that will keep in memory the files added.

// The multiUp function will be called each time our hidden input is changed
document.querySelector('input').addEventListener('change', multiUp, false);

function multiUp(e){
  // if it's the first time we call it
  if(!this.multiFiles){
    // create the array that will keep our files in memory
    this.multiFiles = [];
    // add a pointer to the span where we'll display the file names
    this.__fileHolder = document.querySelector('#fileHolder');
    }
  // each time : empty the fileHolder span
  this.__fileHolder.innerHTML = '';
  var i;
  // add the new files to our array
  for(i = 0; i<this.files.length; i++){
    this.multiFiles.push(this.files[i]);
    }

  for(i = 0; i<this.multiFiles.length; i++){
    // display every file name to our fileHolder
    this.__fileHolder.appendChild(document.createTextNode(this.multiFiles[i].name) );
    // add a button to remove the file from the list
    addDeleteBtn(i, this);
    }
  }

// Tell the add span to act as a trigger to our input
document.querySelector('#add').addEventListener('click', function(){ document.querySelector('input').click()}, false);

function addDeleteBtn(f, input){
  // create the element
  var del= document.createElement('span');
  del.innerHTML = ' (x) ';
  del.className = 'deleteBtn';
  del.title = 'remove this file';
  // add an onclick event
  del.addEventListener('click', function(){
    // update the array
    input.multiFiles.splice(f, 1);
    // update the fileHodler
    input.__fileHolder.innerHTML = '';
    var fileLength = input.multiFiles.length;
    if(fileLength>0){
      for(var i = 0; i<fileLength; i++){
        input.__fileHolder.appendChild(document.createTextNode(input.multiFiles[i].name) );
        addDeleteBtn(i, input);
        }
      }
    else input.__fileHolder.innerHTML = 'No files selected.';
    }, false);
  input.__fileHolder.appendChild(del);
  }
#add{ font-size: 2em; cursor: pointer;}
#fileHolder{ color: rgba(0,0,0,.7); max-width: 80%; font-size: 70%; overflow-x: auto; white-space: nowrap; display: inline-block;}
.deleteBtn{cursor: pointer; color: #000;}
<div class="multiUp">
<span id="add">+</span>
<span id="fileHolder">No files selected.</span>
<input multiple type="file" style="display: none"/>
</div>

You may now access those files by iterating through document.querySelector('.multiUp>input').multiFiles.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • The only issue with this solution is that when I actually go to save and upload it is pulling from the inputs FileList object which will only have the last file selected instead of grabbing the array that we have created – LoganRx Jun 15 '15 at 14:13
  • @LoganRx No, read carefully the last sentence, after the snippet : "You may now access those files by iterating through `document.querySelector('.multiUp>input').multiFiles.` " Actually, you can change `document.querySelector('.multiUp>input')` to any variable you have set for this input. But you have to change what you were doing with `theInput.files` to `theInput.multiFiles` – Kaiido Jun 15 '15 at 14:20
  • 1
    Yea, sorry I misread it, I need to see how the application is grabbing the files right now and direct it away from the FileList object and back to the array, awesome, now to track it down – LoganRx Jun 15 '15 at 14:36