Multipart form handleSubmit method problem

I have created my first multipart form that I am nearly finished working on that is still not posting to my backend database. In terms of the logic to my handleSubmitDive, is this correct? I also have a dispatch to put the dive into the Redux store but do I need to do this if the API will be getting called again?

Uncaught TypeError: Object(...)(...).then is not a function
    handleSubmitDive main.7fef6ae6fc5b0f4fac01.hot-update.js:126
    React 14
    unstable_runWithPriority scheduler.development.js:646
    React 15
    js main.chunk.js:13394
    js main.chunk.js:13494
    Webpack 7
diveLogForm.component.js:104
Uncaught TypeError: Object(...)(...).then is not a function
    handleSubmitDive main.7fef6ae6fc5b0f4fac01.hot-update.js:126
    React 14
    unstable_runWithPriority scheduler.development.js:646
    React 15
    js main.chunk.js:13394
    js main.chunk.js:13494
    Webpack 7
...
Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`. SelectInput.js:342
Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are `5`, `7`, `8`, `1`, `12`, `3`, `13`, `2`, `4`, `10`, `9`, `11`, `6`, `14`. SelectInput.js:342
Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are `1`, `2`, `3`, `4`. SelectInput.js:342
Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are `0`, `1`, `2`, `3`, `4`. SelectInput.js:342
Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are `1`, `2`, `3`, `4`

form

const [dive, setDive] = useState({
            diveTypeID: "",
            diveSchoolNameID: "",
            diveCurrentID: "",
            diveVisibilityID: "",
            diveDate: "",
            diveMaxDepth: "",
            diverUserNumber: "",
            diveVerifiedBySchool: "",
            diveNotes: "",
            diveSpotID: "",
            divePhotos: ""
        });

        const handleChange = (property) => (e) => {
            setDive({
                // override the changed property and keep the rest
                ...dive,
                [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());
        }, []);

        // console.log(fields.data);

        const handleSubmitDive = () => {

            const diveLog = {
                diveTypeID: dive.diveTypeID || undefined,
                diveSchoolNameID: dive.diveSchoolNameID || undefined,
                diveCurrentID: dive.diveCurrentID || undefined,
                diveVisibilityID: dive.diveVisibilityID || undefined,
                diveDate: dive.diveDate || undefined,
                diveMaxDepth: dive.diveMaxDepth || undefined,
                diverUserNumber: dive.diverUserNumber || undefined,
                diveVerifiedBySchool: dive.diveVerifiedBySchool || undefined,
                diveNotes: dive.diveNotes || undefined,
                diveSpotID: dive.diveSpotID || undefined,
                divePhotos: dive.divePhotos || undefined
            }

            // do some stuff with the form
            createDiveLog(diveLog).then((data) => {
                if (data.error) {
                    setDive({ ...dive, error: data.error})
                } else {
                    setDive({ ...dive, error: '', open: true})
                }
            })
            dispatch(addDive(dive));
        }

        function MaterialUIPickers() {
            // The first commit of Material-UI
            const [selectedDate, setSelectedDate] = React.useState(new 
                                      Date('2014-08-18T21:11:54'));

            const handleDateChange = (date) => {
                setSelectedDate(date);
            };
        }

        const classes = useStyles;

        return (

            // <AppBar title="Enter your dive details"></AppBar>
            <>
            <form onSubmit={handleSubmitDive}>

                    <Container maxWidth="lg">
                    <Grid container  fixed spacing={3}
                          direction="row"
                          justify="center"
                          alignItems="center">
                        <Grid item xs={4}>
                        {/*<FormControl className={classes.formControl}>*/}
                            <PopulateDropdown
                                dataList={diveTypeList} // the options array
                                titleProperty={"diveType"} // option label property
                                valueProperty={"diveTypeID"} // option value property
                                label="Dive Type Name" // label above the select
                                placeholder="Select dive type" // text show when empty
                                value={dive.typeID} // get value from state
                                onChange={handleChange("typeID")} // update state on change
                            />
                        {/*</FormControl>*/}
                        </Grid>
                        <Grid item xs={4}>
                            {/*<FormControl className={classes.formControl}>*/}
                                <PopulateDropdown
                                    dataList={diveSchoolList} // the options array
                                    titleProperty={"diveSchoolName"} // option label property
                                    valueProperty={"diveSchoolID"} // option value property
                                    label="Dive School Name" // label above the select
                                    placeholder="Select dive school" // text show when empty
                                    value={dive.schoolNameID} // get value from state
                                    onChange={handleChange("schoolNameID")} // update state on change/>
                                    />
                            {/*</FormControl>*/}
                        </Grid>
                        <Grid item xs={4}>
                            <FormControl className={classes.formControl}>
                                <InputLabel labelId="Enter-the-max-depth">Max Depth</InputLabel>
                                <Select
                                    id="Enter-the-max-depth"
                                    label="Max Depth"
                                    value={dive.maxDepth}
                                    onChange={handleChange("maxDepth")}>
                                    <MenuItem value={0}>10</MenuItem>
                                    <MenuItem value={1}>10-20</MenuItem>
                                    <MenuItem value={2}>20-30</MenuItem>
                                    <MenuItem value={3}>30-40</MenuItem>
                                    <MenuItem value={4}>40+</MenuItem>
                                </Select>
                            </FormControl>
                        </Grid>
                    
                        <Grid item xs={4}>
                        <TextField
                                placeholder="Diver User Number"
                                label="DiverUserNumber"
                                defaultValue={props.user.userID}
                                margin="normal"
                                value={props.user.userID}
                                onChange={handleChange("userID")}
                                fullWidth/>
                        </Grid>
                        <Grid item xs={4}>
                            <TextField
                                placeholder="false"
                                label="verifiedDive"
                                defaultValue={false}
                                margin="normal"
                                value={dive.verifiedBySchool}
                                onChange={handleChange("verifiedBySchool")}
                                fullWidth/>
                        </Grid>
                        <Grid item xs={4}>
                            {/*<FormControl className={classes.formControl}>*/}
                                <PopulateDropdown
                                    dataList={diveSpotList} // the options array
                                    titleProperty={"diveLocation"} // option label property
                                    valueProperty={"diveSpotID"} // option value property
                                    label="Dive Spot" // label above the select
                                    placeholder="Select Dive Spot" // text show when empty
                                    value={dive.diveSpotID} // get value from state
                                    onChange={handleChange("diveSpotID")}/>
                            {/*</FormControl>*/}
                        </Grid>
                        <Grid item xs={4}>
                            <MuiPickersUtilsProvider utils={DateFnsUtils}>
                                <KeyboardDatePicker
                                    disableToolbar
                                    variant="inline"
                                    format="MM/dd/yyyy"
                                    margin="normal"
                                    id="date-picker-inline"
                                    label="Date picker inline"
                                    value={null}
                                    onChange={handleChange("date")}
                                    KeyboardButtonProps={{
                                        'aria-label': 'change date',
                                    }}/>
                            </MuiPickersUtilsProvider>
                        </Grid>
                        <Grid item xs={10}>
                            <TextField
                                placeholder="Dive Notes"
                                label="Dive Notes"
                                margin="normal"
                                multiline={true}
                                rows={4}
                                value={null}
                                onChange={handleChange("notes")}
                                fullWidth/>
                        </Grid>
                        <br />
                        <br />
                        <br />
                        <Grid item xs={4}>
                            <div class="form-control">
                                <label for="photos">Photo Upload</label>
                                <input
                                    type="file"
                                    id="photo"
                                    value={dive.photos}
                                    onChange={handleChange("photos")}/>
                                    {/*<input type="file" className="form-control-photo-uploader" onChange ={this.uploadFile}/>*/}
                            </div>
                        </Grid>
                        <br />
                            <Grid item md={9}>
                            <Button variant="primary" type="submit">
                                Submit</Button>
                            </Grid>
                            <br />
                    </Grid>
                    </Container>
            </form>

action

export const registerUserDive = async (params, credentials, diveLog) => {
    try {
        let response = await fetch('/api/divelog/registerdive' + + params.userId, {
            method: 'POST',
            headers: {
                'Accept': 'application/json',
                'Authorization': 'Bearer ' + credentials.t
            },
            body: diveLog
        })
        return await response.json()

    } catch(err) {
        console.log(err)
    }
}

Well, this is getting complex.

…is still not posting to my backend database. In terms of the logic to my handleSubmitDive, is this correct?

OK, it is failing, but in what way. You need to figure that out. Starting from when you hit that button, when does it stop doing what you expect? Using console.log or break points, can you confirm that handleSubmitDive is called? Can you confirm that your action creator is called? Can you confirm that your reducer is called? Or whatever is listening for that action? Work through it. If you can find exactly where what is happening breaks from what is expected, we can help you a lot better. Or you may be able to figure it out. Trouble shooting is a very important tool for a dev - it takes up a large portion of our time.

Looking at your function, I do see one thing that could be a potential problem.

            createDiveLog(diveLog).then((data) => {
                if (data.error) {
                    setDive({ ...dive, error: data.error})
                } else {
                    setDive({ ...dive, error: '', open: true})
                }
            })
            dispatch(addDive(dive));

There are a few problems here. First, the dispatch is outside the Promise so I think it may get run first. Second, even if we made that synchronous by using async/await or made it moot by putting the dispatch inside the promise, since setDive is itself asynchronous so you have no guarantee that dive is going to have the new value when dispatch is run. One way to solve both would be:

createDiveLog(diveLog).then((data) => {
  const newDive = data.error
    ? { ...dive, error: data.error}
    : { ...dive, error: '', open: true};
   setDive(newDive);
   dispatch(addDive(newDive));
});

There are other ways, but that should work.

Cheers again Kevin. Would I have to amend my action to deal with the newDive const?

I have added the error messages from my console.log above. Is this t do with parsing? I have numbers, text and a file being submitted at the same time.

Would I have to amend my action to deal with the newDive const?

Only if the shape of the data is different. I was assuming that since this was part of dive/setDive that it was all the same data shape.

I have added the error messages from my console.log above

OK, please don’t make major additions to the OP - it confuses people trying to follow this thread later.

Is this t do with parsing?

Those error messages? It seems like you have a few different things going on:

Uncaught TypeError: Object(…)(…).then is not a function
handleSubmitDive main.7fef6ae6fc5b0f4fac01.hot-update.js:126
React 14
unstable_runWithPriority scheduler.development.js:646
React 15
js main.chunk.js:13394
js main.chunk.js:13494
Webpack 7

I don’t know what is going on there, but clearly you are trying to call something as a function that is not a function. These error messages can be a bit cryptic, but clearly it is happening either in handleSubmitDive or in a child of that, some function that is called by that. If you comment out that dispatch, do you still get that error? What about the promise? Just start narrowing it down until you find the problem.

Material-UI: You have provided an out-of-range value undefined for the select component.
Consider providing a value that matches one of the available options or ‘’.
The available values are 1, 2, 3, 4, 5, 6, 7, 8, 9, 10.

This is an MUI problem. I don’t know MUI. But clearly it is telling you that you are giving it an undefined value (or not giving anything value) but it is expecting one of those strings. It is trying to tell you where the problem is. Do some googling. Comment out the MUI stuff and uncomment it one by one until you find the problem.

A big part of being a coder is being a debugger. And a big part of being a debugger is being a detective. So, get out your deerstalker cap and stick a calabash pipe in your mouth and see if you can at least narrow down what line the problems are on.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.