javascript

Is it possible to update FileList?


I have:

<input type="file" id="f" name="f" onchange="c()" multiple />

Every time the user selects a file(s), I build a list of all the selected files by pushing each element of f.files to an array:

var Files = [];
function c() {
  for (var i=0;i<this.files.length;i++) {
    Files.push(this.files[i]);
  };
}

At form submit, f.files contains only the item(s) from the last select action, so I will need to update f.files with the list of FileList items I have accumulated:

const upload=document.getElementById("f");
upload.files = files;

But the second line gives:

Uncaught TypeError: Failed to set the 'files' property on 'HTMLInputElement': The provided value is not of type 'FileList'.

It is not happy that I am assigning it an array. How can I construct a FileList object from the list of FileList elements I have earlier collected?

Side question: I thought Javascript uses dynamic types. Why is it complaining about the wrong type here?


Solution

  • It's like you said

    Failed to set the 'files' property on 'HTMLInputElement': The provided value is not of type 'FileList'.

    you can only set the files with a FileList instance, unfortunately the FileList is not constructible or changeable, but there is a way to get one in a round about way

    /** @params {File[]} files - Array of files to add to the FileList */
    function fileListFrom (files) {
      const b = new ClipboardEvent("").clipboardData || new DataTransfer()
      for (const file of files) b.items.add(file)
      return b.files
    }
    
    const fileList = fileListFrom([
      new File(['content'], 'sample1.txt'),
      new File(['abc'], 'sample2.txt')
    ])
    
    fileInput.onchange = console.log
    fileInput.files = fileList
    
    console.log(fileInput.files)
    <input type="file" id="fileInput" multiple />

    EDIT: Setting input.files might trigger a change event. (seems to have been fixed now) so you might want to toggle the change event listener on and off. (But might not have to anymore. Included a change listener to the demo)