Skip to content

Instantly share code, notes, and snippets.

@guest271314
Last active October 18, 2022 09:49
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save guest271314/7eac2c21911f5e40f48933ac78e518bd to your computer and use it in GitHub Desktop.
Save guest271314/7eac2c21911f5e40f48933ac78e518bd to your computer and use it in GitHub Desktop.
Set the FileList of <input type="file"> to arbitrary File objects
<!DOCTYPE html>
<!-- guest271314 11-12-2017 -->
<!-- see https://stackoverflow.com/questions/47119426 -->
<html>
<head>
</head>
<body>
<script>
const input = document.createElement("input");
const label = document.createElement("label");
const text = document.createTextNode("click to set files\n");
const form = document.createElement("form");
const data = [
new File(["a"], "a.txt"), new File(["b"], "b.txt")
];
// https://github.com/w3c/clipboard-apis/issues/33
class _DataTransfer {
constructor() {
return new ClipboardEvent("").clipboardData || new DataTransfer();
}
}
input.type = "file";
input.name = "files[]";
input.multiple = true;
input.id = "files";
text.textContent = text.textContent.concat(data.map(({
name
}) => name).join(", "), "\n");
label.appendChild(text);
form.appendChild(label);
form.appendChild(input);
document.body.appendChild(form);
// https://github.com/whatwg/html/issues/3222
// https://bugzilla.mozilla.org/show_bug.cgi?id=1416488
label.onclick = e => {
const dt = new _DataTransfer();
for (let file of data) {
dt.items.add(file)
}
if (dt.files.length) {
input.files = dt.files; // set `FileList` of `dt.files`: `DataTransfer.files` to `input.files`
}
for (const file of input.files) {
console.log(file); // `File` objects originally set at `data`, set at `input.files`
}
const fd = new FormData(form); // pass `form` to `fd`: `FormData`
for (const [key, prop] of fd) {
console.log(key, prop); // `File` objects set at `fd`
}
}
// not dispatched at Firefox 57 when set using `input.files = dt.files`
input.onchange = e => {
console.log(e, input.files);
}
</script>
</body>
</html>
@Kaiido
Copy link

Kaiido commented Dec 4, 2017

For Firefox, I believe this is a bug in their implementation of the ClipboardEvent constructor, I am not sure they should let the items property accessible, if I read the specs right, it should be set to null, when no ClipboardEventInit parameter is passed, but I have to admit I don't really understand how this syntax should be read, since the very next example seems to imply that their implementation is the correct one.

But anyway, you are right that the DataTransfer constructor in its current specifications does allow to set arbitrary data to a FileList from scratch... (only chrome does support this constructor at the moment).

I am not sure if this was intended though...

@Kaiido
Copy link

Kaiido commented Dec 5, 2017

Your discovery lead to this proposal: whatwg/html#3269 (comment)
I will also edit the StackOverflow answer giving you credits, you will probably be able to self-answer after your account ban turns-off.

@guest271314
Copy link
Author

@Kaiido ClipboardEvent was used for Firefox, DataTransfer was used for Chromium, to achieve same result at each browser. Did not read the ClipboardEvent specification before trying different approaches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment