Multipart form component "cannot POST / divespotform" not working parseInt issue?

Viewed 186

I have a multipart form that I am nearly finished working on that is still not posting to my backend database. Could this be to do with the fact that I am not parsing my two ID fields as ints correctly?

The two text fields and file field look like they are being sent in the request correctly. Is the random pink/blue/black/red symbols the image being sent to the backend? Should my two ID int fields also be showing here as they are on the same form?

The method I have for my Argument 1 is not an object seems to be related to the diveSpotForm line of my handle submit method. Am I passing the form data to the action correctly? I think I might have over complicated the method not posting straight from the form component.

enter image description here

enter image description here

form component

 const [spot, setSpot] = useState({
        diveLocation: "",
        diveRegionID: parseInt(``),
        diveTypeID: parseInt(``),
        diveSpotDescription: "",
        diveSpotPhotos: "",
        error: ''
    });

    // all onChange functions do the exact same thing, so you only need one
    // pass to a component like onChange={handleChange('typeID')}
    const handleChange = (property) => (e) => {
        setSpot({
            // override the changed property and keep the rest
            ...spot,
            [property]: e.target.value,
        });
    }

    // get access to dispatch
    const dispatch = useDispatch();

    // useEffect with an empty dependency array is the same as componentDidMount
    useEffect(() => {
        dispatch(requireFieldData());
    }, []);

    const handleSubmitDiveSpot = () => {

        const diveSpotForm = new FormData(document.querySelector("diveSpotForm"))
        console.log('diveSpotForm', diveSpotForm);

        const diveSpot = {
            diveLocation: spot.diveLocation || undefined,
            diveRegionID: spot.diveRegionID || undefined,
            diveSpotTypeID: spot.diveSpotTypeID || undefined,
            diveSpotDescription: spot.diveSpotDescription || undefined,
            diveSpotPhotos: spot.diveSpotPhotos || undefined
        }

        // do some stuff with the form
        createDiveSpot(diveSpot).then((data) => {
            const newSpot = data.error
                ? {...spot, error: data.error}
                : {...spot, error: '', open: true};
            setSpot(newSpot);
            dispatch(addDiveSpot(newSpot));
        })
    }


    const classes = useStyles;

    return (

        <form className="diveSpotForm" method="POST" encType="multipart/form-data" onSubmit={handleSubmitDiveSpot}>
            <>
                <Grid container spacing={3}
                      direction="row"
                      justify="center"
                      alignItems="center">
                    <Grid item xs={4}>
                    <FormControl className={classes.formControl}>
                        <PopulateDropdown
                            dataList={diveTypeList}
                            titleProperty={"diveType"} // option label property
                            valueProperty={"diveTypeID"} // option value property
                            name="diveType"
                            placeholder="Dive Type"
                            label="Select Dive Type"
                            value={spot.diveTypeID}
                            onChange={handleChangeInt(parseInt("diveTypeID"))}/>
                    </FormControl>
                    </Grid>
                    <br />
                   ........

                    <br />
                    <Grid item xs={10}>
                        <FormControl fullWidth className={classes.margin}>
                            <TextField
                                label="Description"
                                name="diveSpotDescription"
                                value={spot.diveSpotDescription}
                                onChange={handleChange("diveSpotDescription")}
                                multiline
                                rowsMax={6}/>
                        </FormControl>
                    </Grid>
                    <br />
                    <Grid item xs={12}>
                        <FormControl fullWidth className={classes.margin}>
                            <label for="photos">Photo Upload</label>
                            <input
                                type="file"
                                name="photo"
                                value={spot.diveSpotPhotos}
                                onChange={handleChange("diveSpotPhotos")}/>
                        </FormControl>
                    </Grid>
                    <br />
                    <Grid item xs={3}>
                        <Button variant="primary" type="submit">
                            Submit</Button>
                        <br />
                    </Grid>
                </Grid>
            </>
        </form>

enter image description here

action

export const createDiveSpot = async (diveSpot) => {
    try {
        let response = await fetch('http://localhost:5002/api/divespot/createdivespot', {
            method: 'POST',
            headers: {
                "Content-Type":"multipart/form-data"
            },
            body: new FormData(diveSpot)
        })
        return await response.json()
    } catch(err) {
        console.log(err)
    }
}

backend

exports.createDiveSpot = async (req, res) => {

    const fileNameWithExtension = `${req.file.filename}-${req.file.originalname}`
    const newPath = `./assets/diveSpot/${fileNameWithExtension}`

    fs.rename(req.file.path, newPath, function (err) {
            if (err) {
                console.log(err)
                res.send(500)
            }
            diveSpot.create({
                diveLocation: req.body.diveLocation,
                diveRegionID: req.body.diveRegionID,
                diveSpotTypeID: req.body.diveLocation,
                diveSpotDescription: req.body.diveSpotDescription,
                photos: fileNameWithExtension,
            })
                .catch((err) => {
                    res.status(500).send({
                        message: err.message || 'Some error occurred while creating the post.',
                    })
                })
        }
    )}

route

app.post('/api/divespot/createdivespot', upload.single("diveSpotPhotos"), controller.createDiveSpot);

update

I have also tried the below handleSubmit method and it is still showing the same two argument 1 is not an object errors. As there are two of them it looks like it could be the two id fields ( which are also not appearing on the payload request in the console).

function diveSpotForm(e: React.FormEvent<HTMLFormElement>) {
        e.preventDefault();
        const formData = new FormData();
        formData.append("diveLocation", spot.diveLocation);
        formData.append("diveRegionID", spot.diveRegionID);
        formData.append("diveSpotTypeID", spot.diveSpotTypeID);
        formData.append("diveSpotDescription", spot.diveSpotDescription);
        formData.append("photos", file);
        axios.post("http://localhost:5002/api/divespot/createdivespot", formData);
    }
1 Answers

Hard to figure this out without full code, runnable project etc...
But here are some problems that I could spot in your code.

  1. The FormData constructor should get form object as it's argument, not an object with values (and you are redefining the same diveSpot variable with no reason - remove this let diveSpot = new FormData()).
    https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData

  2. Here is the backend function fixed (at least an attempt)

 exports.createDiveSpot = async (req, res) => {
    try {
        console.log(req.diveSpot);

        // if (req.diveSpot == undefined) {
        //     return res.send(`You must select a file.`);
        // }

        return diveSpot.create({
            diveLocation: req.diveSpot.diveLocation,
            diveRegionID: req.diveSpot.diveRegionID,
            diveSpotTypeID: req.diveSpot.diveSpotTypeID,
            diveSpotDescription: req.diveSpot.diveSpotDescription,
            // You want the file location here 
            diveSpotPhotos: "/assets/" + req.file.filename
            ),
        }).then((diveSpot) => {
            fs.writeFileSync(
                __basedir + "/assets/" + req.file.filename,
                req.file.buffer
            );

            return res.json(`File has been uploaded.`);
        });
    } catch (error) {
        console.log(error);
        return res.send(`Error when trying upload images: ${error}`);
    }
};
  1. You action fixed (Again an attempt)
export const createDiveSpot = async (diveSpot) => {
   return fetch('http://localhost:5002/api/divespot/createdivespot', {
            method: 'POST',
            headers: {
                "Content-Type":"multipart/form-data"
            },
            body: new FormData(diveSpot)
        })
.then(response => response.json())
.catch(err => console.log(err));
       
}
Related