How to disable button on submit form in formik? - reactjs

I have a form in my react component with handleSubmit. What I need to do is when I submit the form(on save click) the save button automatically should get disabled and when I get the response it automatically gets enabled.
handleSubmit = async({ company, email }, { setSubmitting, setErrors }) => {
setSubmitting(true)
const { value: { status, message } } = await this.props.createCompany({ name: company, email })
if (status) {
this.fetchCompanies()
this.closeModal()
} else {
setErrors({ email: message })
}
}
<Formik
initialValues={loginDetails}
validationSchema={loginSchema}
onSubmit={(values, formikProps) => this.handleSubmit(values, formikProps)}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting
}) => (
<form onSubmit={handleSubmit}>
<div className="col-md-12">
<div className="form-group material-textfield">
<input type="text" name="email" value={values.email} onChange={handleChange} className="form-control material-textfield-input"/>
<ErrorMessage component="span" name="email" className="invalid-feedback d-block"/>
<label className="material-textfield-label">Email<span>*</span></label>
</div>
</div>
<button type="submit" className="btn btn-dark btn-lg w-100" disabled={isSubmitting}>Save</button>
</form>
)}
</Formik>
And for this I have used setSubmitting function from formik. But it doesn't work.
Kindly help.

This should help:
const onSubmitHandler = (values, formik) => {
persistYourData(values).then(r => {
formik.setSubmitting(false);
}).catch(error => console.log(error));
}
...
<Button variant="contained" color={"primary"} onClick={pr.handleSubmit} disabled={ ((!(pr.isValid && pr.dirty)) || pr.isSubmitting) }>Submit</Button>

#You can disable the button with **formik.isSubmitting** or **formik.errors** #
<Formik
initialValues={{
email: '',
password: '',
}}
validationSchema={Yup.object({
email: Yup.string().email('Invalid email address').required('Required'),
password: Yup.string().required('Required'),
})}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
});
}}
>
{(formik) => (
<Form>
<h1>Login</h1>
<Field type='email' name='email' />
<br />
<ErrorMessage name='email' />
<br />
<Field type='password' name='password' />
<br />
<ErrorMessage name='password' />
<br />
<button disabled={formik.isSubmitting || formik.errors}>Login</button>
</Form>
)}
</Formik>

Related

React Formik submission

I have an authorization and validation form for registration. I need to to make my form available for click events at my button. At first i added the resetform function in order to notice how my form actually works but after each click nothing happens.
import { Button, TextField } from "#mui/material";
import * as yup from "yup";
import { Formik } from "formik";
export const RegistrationForm = () => {
const validationSchema = yup.object().shape({
name: yup
.string()
.typeError("Должно быть строкой")
.required("Обязательно")
.matches(/^[аА-яЯ\s]+$/, "Имя должно состоять из русских букв"),
secondName: yup
.string()
.typeError("Должно быть строкой")
.required("Обязательно")
.matches(/^[аА-яЯ\s]+$/, "Фамилия должна состоять из русских букв"),
login: yup
.string()
.typeError("Должно быть строкой")
.required("Обязательно"),
password: yup
.string()
.typeError("Должно быть строкой")
.required("Обязательно"),
confirmPassword: yup
.string()
.oneOf([yup.ref("password")], "Пароли не совпадают")
.required("Обязательно"),
email: yup.string().email("Введите верный email").required("Обязательно"),
confirmEmail: yup
.string()
.email("Введите верный email")
.oneOf([yup.ref("email")], "Email не совпадают")
.required("Обязательно"),
});
return (
<>
<header>
<div className="head-btns">
<Button variant="outlined">Зарегистрироваться</Button>
<Button variant="outlined">Авторизоваться</Button>
</div>
</header>
<Formik
initialValues={{
name: "",
secondName: "",
login: "",
password: "",
confirmPassword: "",
email: "",
confirmEmail: "",
}}
validateOnBlur
onSubmit={({ resetForm }) => resetForm()}
validationSchema={validationSchema}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isValid,
dirty,
}) => (
<div className="register">
<TextField
id="outlined-basic"
label="Имя"
variant="outlined"
className="field"
name={"name"}
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
/>
{touched.name && errors.name && (
<p className={"error"}>{errors.name}</p>
)}
<TextField
id="outlined-basic"
label="Фамилия"
variant="outlined"
className="field"
name={"secondName"}
onChange={handleChange}
onBlur={handleBlur}
value={values.secondName}
/>
{touched.secondName && errors.secondName && (
<p className={"error"}>{errors.secondName}</p>
)}
<TextField
id="outlined-basic"
label="Логин"
variant="outlined"
className="field"
name={"login"}
onChange={handleChange}
onBlur={handleBlur}
value={values.login}
/>
{touched.login && errors.login && (
<p className={"error"}>{errors.login}</p>
)}
<TextField
type="password"
id="outlined-basic"
label="Пароль"
variant="outlined"
className="field"
name={"password"}
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{touched.password && errors.password && (
<p className={"error"}>{errors.password}</p>
)}
<TextField
type="password"
id="outlined-basic"
label="Подтвердите пароль"
variant="outlined"
className="field"
name={"confirmPassword"}
onChange={handleChange}
onBlur={handleBlur}
value={values.confirmPassword}
/>
{touched.confirmPassword && errors.confirmPassword && (
<p className={"error"}>{errors.confirmPassword}</p>
)}
<TextField
id="outlined-basic"
label="Email"
variant="outlined"
className="field"
name={"email"}
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
/>
{touched.email && errors.email && (
<p className={"error"}>{errors.email}</p>
)}
<TextField
id="outlined-basic"
label="Подтвердите Email"
variant="outlined"
className="field"
name={"confirmEmail"}
onChange={handleChange}
onBlur={handleBlur}
value={values.confirmEmail}
/>
{touched.confirmEmail && errors.confirmEmail && (
<p className={"error"}>{errors.confirmEmail}</p>
)}
<Button
onClick={handleSubmit}
disabled={!isValid || !dirty}
type="submit"
variant="contained"
className="btn"
>
Зарегистрироваться
</Button>
</div>
)}
</Formik>
</>
);
};
I clicked the button and nothing happens but it should reset all inputs after this action
The onSubmit prop given to the <Formik /> component should be like this:
<Formik
onSubmit={(values, { resetForm }) => resetForm()}
validationSchema={validationSchema}
>
</Formik>
Formik options are passed to the second parameter of the submit handler.
And you don't need to explicitly give your Button onClick handler with type="submit" if you define your form in the HTML form tag.
<Formik
onSubmit={(values, { resetForm }) => resetForm()}
validationSchema={validationSchema}
>
{({ handleSubmit }) => (
<form onSubmit={handleSubmit>
{/* your form */}
<Button
type="submit" // giving type submit to a button enclosed in a form will automatically call handleSubmit method
>
Submit
</Button>
</form>
)}
</Formik>

How disable the auto reset form on submit in formik?

I have a form that i'm controlling by formik, when i fill all the fields and press the buttom submit, the function onSubmit is called and my form have this values reseted.
Sometimes my data is incorrect (like a duplicate email) and i need to persist this data.
How i can do this?
This is my code:
const schema = Yup.object().shape({
login: Yup.string()
.email('Email não possui formato válido')
.required('Informe o email!'),
password: Yup.string().required('Informe a senha!'),
})
const formik = useFormik({
initialValues: {
login: '', password: '', inactive: false
},
validationSchema: schema,
onSubmit: values => {
registerUser(values)
}
})
return (
<form onSubmit={formik.handleSubmit} className={classes.form} noValidate>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography className={classes.observation} component="h6">* Necessário preenchimento do cadastro geral para liberar permissão de telas</Typography>
</Grid>
<Grid item xs={5}>
<TextField
value={formik.values.login}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
helperText={formik.touched.login ? formik.errors.login : ""}
error={formik.touched.login && Boolean(formik.errors.login)}
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="E-mail"
name="login"
autoComplete="email"
/>
</Grid>
<Grid item xs={5}>
<TextField
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
helperText={formik.touched.password ? formik.errors.password : ""}
error={formik.touched.password && Boolean(formik.errors.password)}
variant="outlined"
margin="normal"
required
fullWidth
type="password"
id="password"
label="Senha"
name="password"
/>
</Grid>
<Grid item xs={2}>
<FormControlLabel
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.inactive}
control={<Switch color="primary" />}
label="Inativo"
labelPlacement="top"
/>
</Grid>
<Grid item xs={3}>
<Button fullWidth
variant="contained"
color="primary"
type="submit"
>
Cadastrar
</Button>
</Grid>
</Grid>
</form>
);
Use the Form from formik, and the default is to not reset on submit:
import { Formik, Form } from "formik";
function DemoComp(){
return(
<Formik
initialValues={{ fieldOneVal: "" }}
onSubmit={async (formsData, {setSubmitting, resetForm}) => {
setSubmitting(true)
// async request
// --> if wanted to reset on submit: resetForm();
console.log(formsData)
setSubmitting(false)
}}
>
{({ values, isSubmitting, handleChange, handleBlur, handleSubmit }) => (
<Form>
<input
type="text"
name="fieldOneVal"
value={values.fieldOneVal}
onChange={handleChange}
onBlur={handleBlur}
/>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
)
}
You need to update the following line:
<form onSubmit={(e) => { e.preventDefault(); formik.handleSubmit(e)}} className={classes.form} noValidate>
You need to define the function to be async and as async response handling is not mention in your code so it's hard to give exact solution
<Formik
initialValues={{ fieldOneVal: formvalues.fieldOneVal }}
onSubmit={async (values, { resetForm }) => {
// setFormvalues(({fieldOneVal:values.fieldOneval}) don't know why you're manipulating state
const resp=await someAsyncFunc()
if (resp){
reset the state to initial values}
else{
pop up modal display with errors}
}}
>
I faced the same problem formik resetting the form before i get a response from the server.This solution helped me.
import { Formik, Form } from "formik";
function DemoComp(){
const [formvalues,setFormvalues]= useState({
{ fieldOneVal: "" }
)
return(
<Formik
initialValues={{ fieldOneVal: formvalues.fieldOneVal }}
onSubmit={(values, { resetForm }) => {
setFormvalues(({fieldOneVal:values.fieldOneval})
// async request
if sucess{
reset the state to initial values}
else{
pop up modal display with errors}
}}
>
{({ values, isSubmitting, handleChange, handleBlur, handleSubmit }) => (
<Form>
<input
type="text"
name="fieldOneVal"
value={values.fieldOneVal}
onChange={handleChange}
onBlur={handleBlur}
/>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
)
}

Formik number field accept only positive numbers

I have a form in which I have a number field. I am using formik for this. I need to have an input which only accepts positive numbers.
This is the codesandbox url
You should use regex in onChange event of Number input
Sample code:
const App = () => (
<div className="app">
<Formik
initialValues={{ email: "", rank: -2 }}
onSubmit={async values => {
await new Promise(resolve => setTimeout(resolve, 500));
alert(JSON.stringify(values, null, 2));
}}
validationSchema={Yup.object().shape({
email: Yup.string()
.email()
.required("Required")
})}
>
{props => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
handleReset,
setFieldValue
} = props;
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email" style={{ display: "block" }}>
Email
</label>
<input
id="email"
placeholder="Enter your email"
type="text"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.email && touched.email
? "text-input error"
: "text-input"
}
/>
<label htmlFor="email" style={{ display: "block" }}>
Rank
</label>
<input
id="rank"
placeholder="Enter your email"
type="number"
value={values.rank}
onChange={e => {
e.preventDefault();
const { value } = e.target;
const regex = /^(0*[1-9][0-9]*(\.[0-9]*)?|0*\.[0-9]*[1-9][0-9]*)$/;
if (regex.test(value.toString())) {
setFieldValue("rank", value);
}
}}
onBlur={handleBlur}
/>
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</form>
);
}}
</Formik>
</div>
);
render(<App />, document.getElementById("root"));
Code sanbox link: https://codesandbox.io/embed/formik-example-nut8p?fontsize=14&hidenavigation=1&theme=dark
You can add the attribute min to your input
<input
id="rank"
placeholder="Enter your rank"
type="number"
value={values.rank}
min="1"
onChange={handleChange}
onBlur={handleBlur}
/>
Pass a validate function
// Synchronous validation
const validate = values => {
const errors = {};
if (!values.numberFied < 0) {
errors.numberFied = 'Must be positive';
}
//...
return errors;
};

onchange in a form using formik the value of the field is not updated

I'm new to react, and I'm trying to apply validations to a form.
For some reason when adding the property:
onChange={onChange}
I want to send the values to the parent component. That's why I'm using the onchange.
Nothing I write is shown in my text fields, why does this happen?
export const Son = props => {
const { onChange } = props;
return (
<Formik
initialValues={{
fullname: "",
email: ""
}}
validationSchema={Yup.object().shape({
fullname: Yup.string()
.min(2, "Your name is too short")
.required("Please enter your full name"),
email: Yup.string()
.email("The email is incorrect")
.required("Please enter your email")
})}
onSubmit={(values, { setSubmitting }) => {
const timeOut = setTimeout(() => {
console.log(values);
setSubmitting(false);
clearTimeout(timeOut);
}, 1000);
}}
>
{({
values,
errors,
touched,
handleSubmit,
isSubmitting,
validating,
valid
}) => {
return (
<Form name="contact" method="post" onSubmit={handleSubmit}>
<label htmlFor="fullname">
Fullname
<Field
type="text"
name="fullname"
autoComplete="name"
placeholder="your fullname"
onChange={onChange}
/>
</label>
{<ErrorMessage name="fullname">{msg => <p>{msg}</p>}</ErrorMessage>}
{/*errors.fullname && touched.fullname && <p>{errors.fullname}</p>*/}
<br />
<label htmlFor="email">
Email
<Field
type="email"
name="email"
autoComplete="email"
placeholder="your email"
onChange={onChange}
/>
</label>
<ErrorMessage name="email">{msg => <p>{msg}</p>}</ErrorMessage>
<br />
<button type="submit" disabled={!valid || isSubmitting}>
{isSubmitting ? `Submiting...` : `Submit`}
</button>
</Form>
);
}}
</Formik>
);
};
this is my live code:
https://stackblitz.com/edit/react-qotvwb?file=components/son_component.js
you're not using the formik handleChange at all.
I highlighted the changes that I made in https://stackblitz.com/
and you can test this working here

How to use useState hook in formik forms

I am using formik form and to get make a modal on this form how can i use useState hook ?
FormReq = ({ values, errors, touched, handleChange, isSubmitting, handleBlur }) =>
(
<>
<div className="container">
<Modal email={values.email} password={values.password}/>
</div>
<Form>
<div className="container">
<div className="form">
<Field type="email" name="email" placeholder="Email" onChange={handleChange} onBlur={handleBlur} className="inputField"/>
<Field type="password" name="password" placeholder="Password" onChange={handleChange} className="inputField"/>
<span className="buttonsubmit">
<button disabled={isSubmitting}>Submit</button>
</span>
</div>
</div>
<div className="container errors">
{ touched.email && errors.email && <p>{errors.email}</p> }
{ touched.password && errors.password && <p>{errors.password}</p> }
</div>
</Form>
</>
)
const ContactUs = withFormik({
mapPropsToValues({ email, password}){
return{
email: email || '',
password: password || ''
}
},
validationSchema: Yup.object().shape({
email: Yup.string().email('Email not valid').required('Email is required'),
password: Yup.string().min(9, 'Password must be 9 characters or longer').required('Password is required')
}),
handleSubmit(values, { resetForm }){
console.log(values);
resetForm();
}
})(FormReq)

Resources