I have a form in which I let the user add up to 5 files in a way that I only show one <input type="file">
and if the user do put a file at the <input>
then I update the form adding another input and so on. It works pretty well when I use the file picker and choose a file. But now I’m trying to add an option so the user can just CTRL+V an image clipboard content directly into the <input>
field and then update the form as said before. I also added a loop verifying if the input fields do have content so the user don’t update, like, the 0th input and then a new input emerges for no necessity. And that’s the point that making my code fail as shown below:
EDIT I’ve just added an entire HTML file that simulates the issue:
EDIT 2 This issue didn’t happen under Chromium based Brave browser, I can simulate it under Firefox
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<title>Document</title>
</head>
<body>
<form class="form-post" role="form" method="POST" enctype="multipart/form-data" action="/someroute">
<!-- other inputs... -->
<div id="form-post-file-input-div">
<div class="form-post-file-input-box">
<input class="novo-post-form-item form-post-file-input" name="arquivos[]" type="file" onchange="addNovoInputFile(this, 5)">
</div>
</div>
</form>
<script>
var addNovoInputFile = function(elem, max){
fileInputs = $('.form-post-file-input');
// When this loop is reached from a copypaste event, the content of fileInputs[0].files is empty
// this doesn't happen when I just select a file from filepicker
for(var i=0; i < fileInputs.length; i++)
{
if(fileInputs[i].files.length === 0)
return;
}
// I put this loop so I don't update the form in case, for example, if the user keeps updating a file at the 0th <input>
// but maybe my solution is just changing the logic of this loop
if(fileInputs.length >= max || elem.files.length === 0)
return;
var novoInput = "<div class="form-post-file-input-box">";
novoInput += "<input class="novo-post-form-item form-post-file-input" name="arquivos[]" type="file" onchange="addNovoInputFile(this, " + max + ")">";
novoInput += "</div>"
$(novoInput).appendTo(".form-post #form-post-file-input-div");
};
// New event I just added in order to fill the input with a printscreen content in the clipboard
window.addEventListener('paste', e => {
let inputs = document.getElementsByName('arquivos[]');
let inputToChange = inputs[inputs.length-1];
if(e.clipboardData.files.length > 0){
inputToChange.files = e.clipboardData.files;
addNovoInputFile(inputToChange, 5);
}
});
</script>
</body>
</html>
What exactly is happening is that when I run CTRL+V the second time the 0th element
from the list returned by $('.form-post-file-input')
has the .files
array empty and the 1st
has the content from the clipboard. Why does that happen since when I typed CTRL+V for the first time I did fill the content of .files
(in addEventListener
) and the proof for that is that when I submit
the form the 0th
file is uploaded to the server… but the .files
is empty… I don’t understand why specially because this doesn’t happen when I choose files from the file picker.
2
Answers
The cause is use of
return;
statement which will exit the whole function instead of for loop thus it won’t create another input picker.You must use
break;
instead:to
it worked in chromium based browsers because
fileInputs[i].files.length
was not 0 over there.I have checked above code and unable to reproduce issue which you have mentioned but I have found one another issue.
The issue is when I tried to copy multiple files and pasted it in one go. all the files was pasted in one file input instead of separate input for each pasted files. So I have just fixed those by following issue: