skip to Main Content

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' }
   ]

2

Answers


  1. Chosen as BEST ANSWER

    From the first suggestion of brunnerh, I modified a little bit based on SvelteKit customising use:enhance:

    <script lang="ts">
        import { enhance } from '$app/forms';
        // rest of original code.
    
    </script>
    
    <form action="?/submit" method="post" on:submit={handleSubmit} use:enhance={({ formData }) => {selectedFiles.forEach(f => formData.append('files', f));}}>
        <!-- rest of original code -->
    </form>
    

    Thank you so much for pointing me out my fault.


  2. 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 />
    

    REPL

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search