Reputation: 449
import React, { useState } from "react";
import FileBase64 from "react-file-base64";
import { useDispatch } from "react-redux";
import { makeStyles } from "@material-ui/core/styles";
import { TextField, Select, Input, MenuItem, Button } from "@material-ui/core";
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { updatePost } from "../actions/post";
const useStyles = makeStyles((theme) => ({
textField: {
marginBottom: theme.spacing(2),
},
buttons: {
marginTop: theme.spacing(2),
},
}));
const tags = ["fun", "programming", "health", "science"];
const postSchema = yup.object().shape({
title: yup.string().required(),
subtitle: yup.string().required(),
content: yup.string().min(20).required(),
tag: yup.mixed().oneOf(tags),
});
const EditPostForm = ({ history, post, closeEditMode }) => {
const dispatch = useDispatch();
const [file, setFile] = useState(post?.image);
const { register, handleSubmit, control, errors, reset } = useForm({
resolver: yupResolver(postSchema),
});
const onSubmit = (data) => {
const updatedPost = {
_id: post._id,
...data,
image: file,
};
dispatch(updatePost(post._id, updatedPost));
reset();
setFile(null);
closeEditMode();
};
const classes = useStyles();
return (
<div>
<form noValidate autoComplete="off" onSubmit={handleSubmit(onSubmit)}>
<TextField
id="title"
label="Başlık"
name="title"
variant="outlined"
className={classes.textField}
size="small"
{...register('title')}
error={errors?.title ? true : false}
fullWidth
defaultValue={post?.title}
/>
<TextField
id="subtitle"
label="Alt Başlık"
name="subtitle"
variant="outlined"
className={classes.textField}
size="small"
{...register('subtitle')}
error={errors?.subtitle ? true : false}
fullWidth
defaultValue={post?.subtitle}
/>
<Controller
render={({field}) => (
<Select
{...field}
input={<Input />}
className={classes.textField}
fullWidth
>
{
tags.map((tag, index) => (
<MenuItem {...field} key={index} value={tag}>
{tag}
</MenuItem>
))
}
</Select>
)}
name='tag'
control={control}
error={errors?.tag ? true : false}
defaultValue={tags[0]}
/>
<TextField
id="content"
label="İçerik"
name="content"
multiline
size="small"
{...register('content')}
rows={16}
className={classes.textField}
variant="outlined"
error={errors?.content ? true : false}
fullWidth
defaultValue={post?.content}
/>
<FileBase64 multiple={false} onDone={({ base64 }) => setFile(base64)} />
<div className={classes.buttons}>
<Button color="primary" variant="outlined" onClick={closeEditMode}>
Vazgeç
</Button>{" "}
<Button color="secondary" variant="outlined" type="submit" >
Kaydet
</Button>
</div>
</form>
</div>
);
};
export default EditPostForm;
I have EditPostForm component, component doesn't give any error but when I tried to submit my form onSubmit function is not triggered.
I used react-hook-form to create my form and I used material UI components inside form. When I Click button which has type submit does not trigger onSubmit function which is called inside of handleSubmit. Why onSubmit is not triggered?
Upvotes: 33
Views: 51136
Reputation: 7510
A bit late to the party, but it took me an hour to figure this out.
The submit happens ONLY if there are no validation errors. In my case - I've renamed a field, and therefore validation was failing. The only way to understand that is to use the second parameter of handleSubmit
- be careful, as I thought error
is the second parameter of onSubmit
(which is the first parameter of handleSubmit
):
function onSubmit(values) {} // would be called ONLY if there's no validation error
function onError(errors, event?) {} // get to know what the issue is
<form onSubmit={handleSubmit(onSubmit, onError)}
</form>
Upvotes: 1
Reputation: 21
As others have said, react hook form would not trigger the submitHandler
if there are still errors within the formState.errors
object. It would automatically go to the error handler of the handleSubmit
parameters.
I have done a makeshift workaround that would ignore this case:
<FormProvider {...methods}>
<Card className={classNames('p-0 md:py-2 lg:px-10', wrapperCardClass)}>
<LoadHandler status={recordStatus} errors={recordErrors}>
<form
className="relative flex flex-col gap-4"
onSubmit={(e) => {
methods.clearErrors()
methods.handleSubmit(onSubmit)(e)
}
>
This would clear the errors before handling the submit request. I've used this for my project which is all server-side validation. Hope this answer helps!
Upvotes: 2
Reputation: 1411
For someone who doesn't get this resolved by other solutions mentioned here. Two other possible issues.
type="submit"
attribute in the Button
component.form
element didn't have the input fields and button component in the actual dom. The form contents were rendered inside a modal div in a different node in the DOM tree. Even though we see the form contents as children of FormProvider
, the actual DOM fields were rendered as portal.
So, actual DOM looked likeReact DOM
const FormContent = () => {
return (
<>
<Fields />
<Button />
</>
);
};
const CreateItemButton = () => {
return (
<>
<Button onClick={openModel}>Create</Button>
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
<Modal isOpen={isOpen} onClose={closeModal}>
<FormContent />
</Modal>
</FormProvider>
</>
);
};
HTML: (Actual DOM)
<!-- actual page -->
<button>Create</button>
<form></form>
<!-- somewhere down the line as portal -->
<div class="modal">
<input />
<input />
<button />
</div>
Upvotes: 7
Reputation: 333
Basically the button submits only when all the validation conditions are met(if any) and if there are no field errors. So, its better to check if there are any errors being generated after filling all the fields or while clicking on submit.
Upvotes: 0
Reputation: 167
You need to pass onSubmit and onError both.
Like this:
onPress={handleSubmit(onSubmit, onErrors)}
Upvotes: 14
Reputation: 329
I faced the same error, the problem was that, my register were Boolean and my input was string, and since the value was not required It didn't show errors until I figure out the problem and change register from Boolean to string
Upvotes: 2
Reputation: 644
onSubmit
isn't triggered because you may have form errors
You can get errors
from formState
object (const { formState } = useForm(...)
)
And then use error={formState.errors?.content ? true : false}
in your code
https://react-hook-form.com/api/useform/formstate
See an example here https://codesandbox.io/s/keen-burnell-2yufj?file=/src/App.js
Upvotes: 56