I am writing a file selection form that each time a file is selected, that file will be added to the existing file array. My intention is to submit that array via the form, but after submitting, the array is stringified. I don't know how to handle it, please help me.
This is my code:
<script lang="ts">
let selectedFiles: File[] = [];
function handleSubmit(e: any) {
errorCode = validate(selectedFiles);
if (errorCode) {
console.log(errorCode);
e.preventDefault();
}
}
function handleFileSelect(e: any) {
selectedFiles = [...selectedFiles, e.target.files[0]];
}
// Create ref to DOM element
let fileInput: HTMLInputElement;
</script>
<form action="?/submit" method="post" on:submit={handleSubmit}>
<div>
<label for="files">Click "+" to add file</label>
<button on:click={(e) => {e.preventDefault(); fileInput.click();}}>
<span>+</span>
</button>
<input type="file" accept={allowedExtensions} on:change={handleFileSelect} on:invalid={handleInvalid} bind:this={fileInput} hidden/>
<input type="hidden" name="contest" value={contest.id} />
<input type="hidden" name="user" value={data.user.id} />
<input type="hidden" name="files" value={selectedFiles} />
<p>Selected files: {getFileNames(selectedFiles).join(', ')}</p>
<br />
<button type="submit" class="btn btn-primary w-full">Submit</button>
</div>
</form>
I logged request.formData() and it came out like this:
[Symbol(state)]: [
{
name: 'files',
value: '[object File],[object File],[object File]'
},
{ name: 'contest', value: '5bvod8teq8kh7yn' },
{ name: 'user', value: 'dvkw0v6uz31zag2' },
{ name: 'score', value: '0' }
]
I expected it like this:
[Symbol(state)]: [
{ name: 'files', value: [File] },
{ name: 'files', value: [File] },
{ name: 'files', value: [File] },
{ name: 'contest', value: '5bvod8teq8kh7yn' },
{ name: 'user', value: 'dvkw0v6uz31zag2' },
{ name: 'score', value: '0' }
]
If you create new form data, you could add the files to that, though in that case the request has to be made manually/asynchronously. When using SvelteKit, the enhance
action should be used which already does this and gives access to the form data in the callback.
<script>
function onSubmit({ formData }) {
files.forEach(f => formData.append('files', f));
}
</script>
<form
method="POST"
use:enhance={onSubmit}> ...
It is also possible to set file lists on inputs, which could be done as well.
<script>
let submittedFileInput;
function onSubmit() {
const transfer = new DataTransfer();
files.forEach(f => transfer.items.add(f));
submittedFileInput.files = transfer.files;
}
</script>
...
<input bind:this={submittedFileInput} style="display: none"
name="files" type="file" multiple />