1

I'm struggling to access the FileList from an input type="file" submitted from a React frontend to a Node backend. From my browser console I can see that the desired list of files is being submitted as the form data.

Eventually worked out that the FileList looks like an array but isn't! So got the length of it using Object.keys (interestingly other answers recommended here didn't work for me).

But no matter what I try I can't access the individual File objects... I can now cycle through the items in the FileList but I need to be able to get the filename to upload/move it to a new location on my server. It looks like they're empty objects in node but the browser is showing that it's sending the information I need.

Why are the objects I am iterating through empty?

I'm stumped.

Thanks for your help!


Browser Console Output

Console output

Node.js

router.post("", (req, res) => {
    
  var tempFiles = req.body.files;

  var fileCount = Object.keys(tempFiles).length;

  console.log("FileList Keys: " + Object.keys(tempFiles));
  console.log("Length: " + Object.keys(tempFiles).length);
  console.log("Object Length: " + Object.keys(tempFiles['0']).length);
  
  // Loop through files
  for (let i = 0; i < fileCount; i++) {

    let file = tempFiles[i];
    console.log(tempFiles[i]);

  }

}

Node console output:

FileList Keys: 0,1
Length: 2
Object Length: 0
{}
{}

React Form

import React from 'react';
import axios from 'axios';
import {useState} from 'react';
import { useForm } from "react-hook-form";
import { Stack, Input ,InputRightElement, InputGroup, Button, FormControl, FormLabel, FormHelperText, Checkbox, Radio, RadioGroup } from '@chakra-ui/react';

import BasicBanner from '../../core/components/banners/BasicBanner';


export default function UploadEvidence(props) {
    
    const [data, setData] = useState("");
    const [formMessage, setFormMessage] = useState("");
    const { register, formState: { errors }, handleSubmit } = useForm();
    const onError = (errors, e) => console.log(errors, e);

    const onSubmit = (data, e) => {
        console.log(data);
        axios.post('http://localhost:5000/api/uploads', data)
        .then(function (response) {
            console.log(response);
            setFormMessage("Upload successful");
        })
        .catch(function (error) {
            console.log(error);
            setFormMessage("Error uploading");
        });
    }

    return (
        <form onSubmit={handleSubmit(onSubmit, onError)} enctype="multipart/form-data">
            
            <Stack spacing="10">
            {formMessage && 
                <BasicBanner message={formMessage} />
            }

            
            <Input
              type="file"
              accept="pdf/*"
              multiple
              {...register("files", {required: true })}
              aria-invalid={errors.active ? "true" : "false"}
              />

            </Stack>

            <FormControl mt={4}>
                <Button type="submit" colorScheme='blue'>Save</Button>
            </FormControl>

        </form>

    )
}

Node server.js

const express = require('express')
const PORT = process.env.PORT || 5000
const app = express()
const bodyParser = require("body-parser");
const fileupload = require("express-fileupload");
var cors = require('cors');

app.use(cors());
app.use(fileupload());
app.use(express.static("files"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

... Routes ...
 
Oliver Trampleasure
  • 3,293
  • 1
  • 10
  • 25
  • Not sure what type is `tempFiles`, maybe try using `Array.from(tempFiles)` and loop that instead? – Camilo Nov 23 '22 at 17:36
  • I believe it's a FileList from the browser console screenshot. Printing the results of `Array.from(tempFiles)` to the console gives me `[]` and the length is `0`. – Oliver Trampleasure Nov 23 '22 at 17:41
  • Does this answer your question? [Can't use forEach with Filelist](https://stackoverflow.com/questions/40902437/cant-use-foreach-with-filelist) – Camilo Nov 23 '22 at 17:44
  • I've read that answer, my main question isn't about how to cycle through the objects because my code above that is doing it, but why the items I am iterating through are empty (i.e. no `file` type data:`{name: 'xxx.pdf', lastmodified: '...', ... }`) – Oliver Trampleasure Nov 23 '22 at 17:47
  • Maybe try with [`FileList.item()`](https://developer.mozilla.org/en-US/docs/Web/API/FileList/item). – Camilo Nov 23 '22 at 18:06
  • That silently fails unfortunately, no error is displayed in the console but it stops the function – Oliver Trampleasure Nov 23 '22 at 18:17
  • What's the result of loging `req.body.files`? – Camilo Nov 23 '22 at 18:20
  • the log result of `req.body` is `{ files: { '0': {}, '1': {} } }` – Oliver Trampleasure Nov 23 '22 at 18:37
  • Maybe the file data is being lost further up the chain? Am I meant to add something/change something at the `app.use(...)` stage? But it worked fine when I was testing the back end and submitted a single file as `form-data` via Postman – Oliver Trampleasure Nov 23 '22 at 18:38
  • Yes, there seems to be something wrong before the request reaches your handler. – Camilo Nov 23 '22 at 20:15
  • In case anyone finds themselves here in the future this tutorial helped me create what I needed - https://www.commoninja.com/blog/handling-multiple-file-uploads-with-react-hook-form – Oliver Trampleasure Nov 24 '22 at 23:52

0 Answers0