(React, Formik & Yup) Disable or/and change a class of the submit button - reactjs

So, I've made a registration form in the React App, using Bootstrap for the style, Formik and Yup for the validation. I want to change a Submit Button class to 'btn-outline-danger' and make it disabled till the form inputs are valid. I know it doesn't affect the real functionality, but anyways I'd like to manipulate with the button's style.
import React from 'react';
import { Button, Form as FormStrap } from 'react-bootstrap';
import { Link } from 'react-router-dom';
import * as yup from 'yup';
import { Formik, Form, Field } from 'formik';
const REGISTRATION_SCHEMA = yup.object().shape({
name: yup
.string()
.min(2, 'Too Short!')
.max(24, 'Too Long!')
.required('Required'),
email: yup.string().email('Invalid email').required('Required'),
password: yup
.string()
.min(6, 'Too Short!')
.max(14, 'Too Long!')
.required('Required'),
passwordConfirmation: yup
.string()
.oneOf([yup.ref('password'), null], 'Passwords do not match'),
});
export default function RegistrationForm() {
return (
<>
<Formik
validationSchema={REGISTRATION_SCHEMA}
initialValues={{
name: '',
email: '',
password: '',
passwordConfirmation: '',
}}
onSubmit={(values) => {
// same shape as initial values
console.log(values);
}}
// validate={validate}
>
{({ handleSubmit, handleChange, values, touched, errors }) => (
<Form id='registration-form' onSubmit={handleSubmit}>
<FormStrap.Group className='mb-3' controlId='registration-name'>
<FormStrap.Label>Name</FormStrap.Label>
<Field
className='form-control'
type='text'
placeholder='Enter name'
name='name'
value={values.name}
onChange={handleChange}
/>
{errors.name && touched.name ? (
<FormStrap.Text>{errors.name}</FormStrap.Text>
) : null}
</FormStrap.Group>
<FormStrap.Group className='mb-3' controlId='registration-email'>
<FormStrap.Label>Email </FormStrap.Label>
<Field
className='form-control'
type='email'
placeholder='Enter email'
name='email'
value={values.email}
onChange={handleChange}
/>
{errors.email && touched.email ? (
<FormStrap.Text>{errors.email}</FormStrap.Text>
) : null}
</FormStrap.Group>
<FormStrap.Group className='mb-3' controlId='registration-password'>
<FormStrap.Label>Password</FormStrap.Label>
<Field
className='form-control'
type='password'
placeholder='Enter password'
name='password'
value={values.password}
onChange={handleChange}
/>
{errors.password && touched.password ? (
<FormStrap.Text>{errors.password}</FormStrap.Text>
) : null}
<Field
className='mt-2 form-control'
type='password'
placeholder='Confirm password'
name='passwordConfirmation'
value={values.passwordConfirmation}
onChange={handleChange}
/>
{errors.passwordConfirmation && touched.passwordConfirmation ? (
<FormStrap.Text>{errors.passwordConfirmation}</FormStrap.Text>
) : null}
</FormStrap.Group>
<FormStrap.Group className='mb-3' controlId='registration-submit'>
<Button variant='success' type='submit' disabled={!errors}>
Sign Up
</Button>
</FormStrap.Group>
<FormStrap.Group className='mb-3'>
<FormStrap.Text className='text-muted'>
Already have an account? <Link to='/login'>Sign in now</Link>
</FormStrap.Text>
</FormStrap.Group>
</Form>
)}
</Formik>
</>
);
}

I will rewrite just the button part
<FormStrap.Group className='mb-3' controlId='registration-submit'>
<Button
variant='success'
type='submit'
disabled={Object.keys(errors).length > 0}
className={`${Object.keys(errors).length > 0 ? 'btn-outline-danger': ''}`}>
Sign Up
</Button>
</FormStrap.Group>

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>

Yup Was Not Working With Formik and also not provide any type of error

Yup Validation Not Working I Also tried Like This import Yup from 'yup' But Still Not Working.., when I create a simple validate Function without YUP it was worked fine. but when I use YUP that time Validation Not Work.
Added Form Component
import React from 'react';
import { useFormik } from 'formik';
import * as Yup from 'yup';
const initialValues = {
name : "",
surname : "",
address : ""
}
const validateSchema = Yup.object({
name: Yup.string().required('This Field is Required'),
surname: Yup.string().required('This Field is Required'),
address: Yup.string().required('This Field is Required')
});
const onSubmit = values =>{
console.log('FormData->',values);
}
function Form() {
const formik = useFormik({
initialValues ,
onSubmit ,
validateSchema
})
return (
<div className="container x col-md-4 col-md-offset-4" >
<form onSubmit={formik.handleSubmit} >
<div className="form-group">
<input autoComplete="off" onBlur={formik.handleBlur} onChange={formik.handleChange}
value={formik.values.name} name="name" className="name form-control-lg" placeholder="Enter A Name" />
<small>
{formik.touched.name && formik.errors.name ? <div className="error"> {formik.errors.name} </div> : null}
</small>
</div>
<div className="form-group">
<input autoComplete="off" onBlur={formik.handleBlur} onChange={formik.handleChange}
value={formik.values.surname} name="surname" className="surname form-control-lg" placeholder="Enter A Surname" />
<small> { formik.touched.surname && formik.errors.surname ? <div className="error"> {formik.errors.surname} </div> : null} </small>
</div>
<div className="form-group">
<input autoComplete="off" onBlur={formik.handleBlur} onChange={formik.handleChange} value={formik.values.address}
name="address" className="address form-control-lg" placeholder="Enter A Address" />
<small> {formik.touched.address && formik.errors.address ? <div className="error"> {formik.errors.address} </div> : null} </small>
</div>
<button className="btn btn-danger" >Submit</button>
</form>
</div>
)
}
export default Form;
The valid option here is validationSchema not validateSchema. Just set the right one:
const validationSchema = Yup.object({
// ...
});
useFormik({
// ...
validationSchema
})
To use formik and yup, first you have you do npm install yup and npm install formik. if your yarn user then do yarn add formik and yarn add yup.
after that follow this code.
import {Formik} from 'formik';
import * as yup from 'yup';
//functional component am using
export const Auth = () => {
const initialFormValue ={
email: '',password: '',};
const SignInSchema = yup.object().shape({
email: yup.string().email('Invalid Email').required('Email is Required'),
password: yup.string().min(5, 'Too Short').required('Password is Required'),
})
<Formik initialValues={initialFormValue} validationSchema={SignInSchema}
onSubmit={values => console.log(values)}>
{({values, errors, touched, handleChange, handleBlur,
handleSubmit,isSubmitting,
isValid}) => (
<>
<input name='email' type='email' handleChange={handleChange} value=
{values.email} onBlur={handleBlur} label='Email' />
{errors.email && touched.email ? (<Error>{errors.email}</Error>): null}
<input name='password' type='password' handleChange={handleChange} value=
{values.password} onBlur={handleBlur} label='Password' />
{errors.password && touched.password ? (<Error>{errors.password}</Error>):
null}
<button onClick={handleSubmit} type="submit">Send</button>
</>
) }
</Formik>
)}
its not necessary for you to define initial value outside you can do inside formik too <Formik initialValues={email: '', password: ''}> </Formik>
i hope this will help you thank you.

formik rendering an element when input field is clicked in react?

I am trying to make a simple login form i want to render an element when an input field is clicked . I have done this in normal react form by rendering an element by changing the value of a boolean variable to true and when the input is written if the user touch somewhere else then the element disapears . kind of toggle thing . but i don't know hoe to do this in formik. my code looks like this.
import React from "react";
import { Formik } from "formik";
import * as EmailValidator from "email-validator";
import * as Yup from "yup";
const ValidatedLoginForm = () => (
<Formik
initialValues={{ email: "", password: "" }}
onSubmit={(values, { setSubmitting }) => {
console.log(values);
console.log("hello there ");
}}
validationSchema={Yup.object().shape({
email: Yup.string()
.email()
.required("Required"),
password: Yup.string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number.")
})}>
{props => {
const {
values,
touched,
errors,
isSubmitting,
handleChange,
handleBlur,
handleSubmit
} = props;
return (
<div className="container">
<div className="row">
<form onSubmit={handleSubmit}>
<br />
<input
name="email"
type="text"
placeholder="Enter your email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
className={errors.email && touched.email && "error"}
/>
<br />
<br />
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
<br />
<input
name="password"
type="password"
placeholder="Enter your password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
className={errors.password && touched.password && "error"}
/> <br />
<br />
{errors.password && touched.password && (
<div className="input-feedback">{errors.password}</div>
)}
<button type="submit" disabled={isSubmitting}>
Login
</button>
</form>
</div>
<div className="row">
<button className="btn btn-default">Value</button>
</div>
</div>
);
}}
Maybe this will help you. Try to add function to onBlur prop then handle handleBlur function.
onBlur={(e) => {
handleBlur(e);
// here handle component showing
}}

Submitting Formik form data to firebase database in react

I am trying to figure out how to send form data form a Formik form to a Firebase database in my react app.
I have a form as follows:
import React from 'react'
import { Link } from 'react-router-dom'
// import { Formik } from 'formik'
import { Formik, Form, Field, ErrorMessage, withFormik } from 'formik';
import * as Yup from 'yup';
import { Badge, Button, Col, Feedback, FormControl, FormGroup, FormLabel, InputGroup } from 'react-bootstrap';
import Select from 'react-select';
import firebase from '../../../firebase';
const style1 = {
width: '60%',
margin: 'auto'
}
const style2 = {
paddingTop: '2em',
}
const style3 = {
marginRight: '2em'
}
const style4 = {
display: 'inline-block'
}
const options = [
{ value: 'author', label: 'Author' },
{ value: 'reviewer', label: 'Reviewer' },
];
class Basic extends React.Component {
state = {
selectedOption: null,
}
handleChange = (selectedOption) => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
}
render() {
const { selectedOption } = this.state;
return (
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
password: '',
confirmPassword: '',
selectedOption: null
}}
validationSchema={Yup.object().shape({
firstName: Yup.string()
.required('First Name is required'),
lastName: Yup.string()
.required('Last Name is required'),
email: Yup.string()
.email('Email is invalid')
.required('Email is required'),
selectedOption: Yup.string()
.required('It will help us get started if we know a little about your background'),
password: Yup.string()
.min(6, 'Password must be at least 6 characters')
.required('Password is required'),
confirmPassword: Yup.string()
.oneOf([Yup.ref('password'), null], 'Passwords must match')
.required('Confirm Password is required')
})}
// onSubmit={fields => {
// alert('SUCCESS!! :-)\n\n' + JSON.stringify(fields, null, 5))
// }}
// onSubmit={handleSubmit}
render={({ errors, status, touched }) => (
<Form style={style1}>
<h1 style={style2}>Get Started</h1>
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<Field name="firstName" type="text" className={'form-control' + (errors.firstName && touched.firstName ? ' is-invalid' : '')} />
<ErrorMessage name="firstName" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" type="text" className={'form-control' + (errors.lastName && touched.lastName ? ' is-invalid' : '')} />
<ErrorMessage name="lastName" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<Field name="email" type="text" placeholder="Please use your work email address" className={'form-control' + (errors.email && touched.email ? ' is-invalid' : '')} />
<ErrorMessage name="email" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<Field name="password" type="password" className={'form-control' + (errors.password && touched.password ? ' is-invalid' : '')} />
<ErrorMessage name="password" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="confirmPassword">Confirm Password</label>
<Field name="confirmPassword" type="password" className={'form-control' + (errors.confirmPassword && touched.confirmPassword ? ' is-invalid' : '')} />
<ErrorMessage name="confirmPassword" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="selectedOption">Which role best describes yours?</label>
<Select
value={selectedOption}
onChange={this.handleChange}
options={options}
/>
</div>
<div className="form-group" >
<label htmlFor="consent">By registering you accept the <Link to={'/Terms'}>Terms of Use</Link> and <Link to={'/Privacy'}>Privacy Policy</Link> </label>
</div>
<div className="form-group">
<Button variant="outline-primary" type="submit" style={style3} id="submitRegistration">Register</Button>
</div>
</Form>
)}
/>
);
}
}
export default Basic;
I have a database in firebase (cloud firestore) with a collection called Registrations that has fields named the same as each of these form fields.
I have spent the day following tutorials that seem to be made for react before Formik. There's not much point to showing all the things I've tried and failed at for the day - they're clearly not written with Formik in mind. I can't find a way to write the onSubmit so that Formik can give the data to Firebase.
Has anyone found a current tutorial or know how to do this?
I've used Formik and Firebase in this Open-Source React project. Maybe this is what you're looking for :)
Expertizo React Native Kit

Is it possible to timeout and hide the error message of forms after some time in Formik?

How can I hide the error message of forms after some time in Formik (React form library).
Is there any method in Formik?
It shows Name is Required, Email is required, Message is required. But I want to hide it after sometime.
Here is my code :
import React from 'react';
import { withFormik, Form, Field } from 'formik';
import * as Yup from 'yup';
import './contact.scss';
const Contact = ({ errors, touched }) => {
return (
<section className="c-section c-contact u-padding-v-xlarge">
<h1>Get in touch</h1>
<p>We&apos;ll love to hear from you!</p>
<Form>
<div>
{touched.name && errors.name ? (
<p style={{ color: 'red' }}>{errors.name}</p>
) : null}
<Field
id="Name"
type="text"
name="name"
autoComplete="name"
placeholder="Your Name"
/>
</div>
<div>
{touched.email && errors.email ? (
<p style={{ color: 'red' }}>{errors.email}</p>
) : null}
<Field
id="message"
type="email"
name="email"
autoComplete="email"
placeholder="Your Email"
/>
</div>
<div>
{touched.message && errors.message ? (
<p style={{ color: 'red' }}>{errors.message}</p>
) : null}
<Field
component="textarea"
name="message"
id="message"
placeholder="Your Message"
/>
</div>
<button type="submit" className="button button--success button--block">
Send Message
</button>
</Form>
</section>
);
};
export default withFormik({
mapPropsToValues: () => ({
name: '',
email: '',
message: '',
}),
validationSchema: Yup.object().shape({
name: Yup.string().required('Name is required'),
email: Yup.string()
.email('Email not valid')
.required('Email is required'),
message: Yup.string().required('Message is required'),
}),
handleSubmit: (values, { resetForm }) => {
// Handle http request here
console.log(values);
setTimeout(resetForm(), 2000);
},
})(Contact);
I have tried setTimeout(resetForm(), 2000); passing resetForm but it doesn't work. Any alternative?
When you do setTimeout(resetForm(), 2000) you are not passing the function (you are calling it) to the setTimeout. You should do setTimeout(resetForm, 2000). If you want to reset errors you can use setErrors like in example https://codesandbox.io/s/941jzvx01p

Resources