Formik ErrorMessage not appearing on browser - reactjs

In this simple form, I take description and category(select) from user inputs.
I try to display error by rendering prior, and it worked completely fine.
When I reafactored, using ErrorMessage from formik, it stopped showing error message on the browser.
I read the coumentation, and there seems no issue regarding my code below.
Any suggestion or something I didn't notice?
const initialValues = {
description: '',
category: '',
};
const validationSchema = Yup.object({
description: Yup.string().required('Required'),
category: Yup.string().required('Required'),
});
const onSubmit = (values) => {
console.log('Form data', values);
};
const AddForm = () => {
return (
<Formik
initialValues={initialValues}
ValidationSchema={validationSchema}
onSubmit={onSubmit}
>
<Form className='container'>
<div className='form-control'>
<label htmlFor='description'></label>
<Field
type='text'
id='description'
name='description'
placeholder='Enter Description...'
/>
<ErrorMessage name='description' />
</div>
<div className='form-control'>
<label htmlFor='category'></label>
<Field name='category' as='select'>
<option value='' label='Select Category' />
<option value='home' label='Home' />
<option value='work' label='Work' />
<option value='entertainment' label='Entertainment' />
</Field>
<ErrorMessage name='category' />
</div>
<button type='submit'>Submit</button>
</Form>
</Formik>
);
};

Its happening because you mistyped validationSchema to ValidationSchema i.e
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
>
Here is demo working fine: https://codesandbox.io/s/spring-field-ieip1?file=/src/App.js

Related

How to solve uncontrolled warning in react formik?

Let's say we have a form that has two fields, first name, and last name.
I want to control this form using React Formik and I have simulated API response using setTimeout
The problem is that when API returns null for some properties, I get the dirty uncontrolled warning of React.
I'm using Formik's 'name' prop to mutually bind my JSON to my form inputs.
How can I solve this problem?
Here's my code:
export default function Home() {
const [initialValues, setInitialValues] = useState({
firstName: '',
lastName: '',
});
useEffect(() => {
console.log(initialValues);
}, [initialValues]);
useEffect(() => {
setTimeout(() => {
setInitialValues({ firstName: 'api', lastName: null });
}, 3000);
}, []);
const onSubmit = (values) => {
console.log(values);
};
const validationSchema = Yup.object({
firstName: Yup.string().required('Required'),
lastName: Yup.string().required('Required'),
});
return (
<div>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
validateOnChange={false}
validateOnBlur={false}
enableReinitialize
>
<Form>
<br />
<div>
<Field
type="text"
id="firstName"
name="firstName"
label="firstName"
placeholder="First Name"
/>
<ErrorMessage name="firstName" />
</div>
<br />
<div>
<Field
type="text"
id="lastName"
name="lastName"
placeholder="Last Name"
/>
<ErrorMessage name="lastName" />
</div>
<br />
<button type="submit">Submit</button>
</Form>
</Formik>
</div>
);
}
And here's an online sample in StackBlits
Don't trust the data coming back from your API to be complete, then. Pull each value you need into a new object with a default value of an empty string. Something like
let newInitialValues = {};
newInitialValues.firstName = apiResult.firstName ? apiResult.firstName : '';
newInitialValues.lastName = apiResult.lastName ? apiResult.lastName : '';
This ensures you'll always have a valid value.

Form data filled does not show on console using react hooks

I have a form built with formik and yup, but after filling the form, the data did not show on the console and when i clicked the next button, it does not take to the next page.
The validations are working.
.
.
.
const navigate = useNavigate()
const initialValues = {
phone: "",
email: ""
}
const validationSchema = Yup.object({
phone: Yup.string().required('Required'),
email: Yup.string().required('Required').email('Invalid email format'),
})
const onSubmit = values => {
console.log('Form data', values)
navigate("/NextPage")
}
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}>
<Form>
<div className="mb-3">
<label className='form-label'>Phone Number</label><br/>
<Field type='tel' name='phone' className='place-holder white-bg' id='phone'/>
<ErrorMessage name='phone'>
{ (errorMsg) => <div className='error'>{errorMsg}</div> }
</ErrorMessage>
</div>
<div className="mb-3">
<label className='form-label'>Email address(optional)</label><br/>
<Field type='email' name='email' className='place-holder white-bg' id='email'/>
<ErrorMessage name='email'>
{ (errorMsg) => <div className='error'>{errorMsg}</div> }
</ErrorMessage>
</div>
<Button variant="primary" type="submit" className="buy-token-next-btn">
Next
</Button>
</Form>
</Formik>

React + Formik + Yup async validation

Formik + yup
validation with .test() triggers on change on every field
example:
i have a validation schema:
const schemaValidation = yup.object().shape({
name: yup.string().required(),
email: yup.string().email().required()
.test( // it runs even if previous validation failed!
'checkEmailExists', 'email already taken.',
// it triggers on every onBlur
email => { console.log('email registration runs') return Promise.resolve(true)}
),
other: yup.string().required()
.test(
'checkOthers', 'error',
val => {console.log('other validation runs'); return Promise.resolve(true)}
)
})
render function on my react component looks like:
...
render () {
return(
<Formik
validateOnChange={false}
validateOnBlur={true}
initialValues={{
name: '',
email: '',
other: ''
}}
validationSchema={schemaValidation}
onSubmit={this.handleSubmit}
>
{(props) => (
<Form>
<div className="field">
<Field className="input" type="email" name="email" placeholder="Email" />
<ErrorMessage name="email" />
</div>
<div className="field">
<Field className="input" type="text" name="name" placeholder="Name"/>
<ErrorMessage name="name" />
</div>
<div className="field">
<Field className="input" type="text" name="other" placeholder="Other"/>
<ErrorMessage name="other" />
</div>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
)
so after every single field changed I receive messages from all .test() validators in console:
email registration runs
other validation runs
versions:
react: 16.13.1
formik: 2.1.4
yup: 0.28.4
By default formik validates after change, blur and submit events. Your code disables validation after change events with validateOnChange={false}. In order to only validate on submit events, try setting validateOnBlur to false too.
https://jaredpalmer.com/formik/docs/guides/validation#when-does-validation-run
https://jaredpalmer.com/formik/docs/api/formik#validateonblur-boolean
Hello everyone in 2022,
I understand a lot of formik has changed over the years - but thought I share a relevant solution that's using touched property, feel free to peek at https://codesandbox.io/s/stack-overflow-54204827-llvkzc.
And also shared for another StackOverflow question here, React Native Form Validation.
In summary, it's basically used like below (with yup outside of this snippet), to decide whether to show (if any) input validation errors:
<Formik
initialValues={{
email: "",
password: ""
}}
validationSchema={LoginSchemaA}
onSubmit={(
values: Values,
{ setSubmitting }: FormikHelpers<Values>
) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 500);
}}
>
{({ errors, touched }) => (
<Form>
<label htmlFor="email">Email</label>
<Field
id="email"
name="email"
placeholder="john.doe#email.com"
type="email"
/>
{errors.email && touched.email ? (
<div style={{ color: "red" }}>{errors.email}</div>
) : null}
<label htmlFor="password">Password</label>
<Field id="password" name="password" type="password" />
{errors.password && touched.password ? (
<div style={{ color: "red" }}>{errors.password}</div>
) : null}
<button type="submit">Submit</button>
</Form>
)}
</Formik>
And as package.json reference, below are the defined versions:
"dependencies": {
...
"formik": "2.2.9",
...
"yup": "0.32.11"
},
Hope this helps for those on these mentioned formik and yup versions above!

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 add Radio Button in Formik Validations Reactjs?

I am using Formik for Validating my Registration form I want to add validate gender via radio button how can I do that. I am not able to add radio button.
This is what I have done:-
const SignupSchema = Yup.object().shape({
email: Yup.string()
.email('Invalid email')
.required('Required'),
password: Yup.string()
.min(4, 'Password Must be four characters long!')
.max(20, 'Too Long!')
.required('Required'),
});
class Register extends Component {
render() {
return (
<Formik
initialValues={{
email: '',
password:'',
gender:'',
}}
validationSchema={SignupSchema}
onSubmit={values => {
console.log(values);
}}
>
{({ errors, touched }) => (
<Form>
<Field style={customStyles.textfield} placeholder="Email" name="email" type="email" />
{errors.email && touched.email ? <div}>{errors.email}</div> : null}
<Field placeholder="Enter Password" name="password" type="password" />
{errors.password && touched.password ? <div >{errors.password}</div> : null}
<button type="submit">Submit</button>
</Form>
)}
</Formik>
</div>
)
}
}
change gender initialValues as male
<Field
name="gender"
render={({ field }) => (
<>
<div className="radio-item">
<input
{...field}
id="male"
value="male"
checked={field.value === 'male'}
name="type"
type="radio"
/>
<label htmlFor="male">Male</label>
</div>
<div className="radio-item">
<input
{...field}
id="female"
value="female"
name="type"
checked={field.value === 'female'}
type="radio"
/>
<label htmlFor="female">Female</label>
</div>
</>
)}
/>
This solution gives you the chance to have more than 2 options.
Let say you have a file called Main.js and you want to put a radio button input in it. First, provide a list of options for your radio button in the Main.js
const radioOptions = [
{ key: 'Option 1', value: 'value 1' },
{ key: 'Option 2', value: 'value 2' },
{ key: 'Option 3', value: 'value 3' }
];
Next, create a RadioButton.js file with below code
import React from 'react';
import { Field } from 'formik';
const RadioButton = (props) => {
const { label, name, options, ...rest } = props;
return (
<div>
<label htmlFor={name}>{label}</label>
<Field name={name} {...rest} >
{
({ field }) => {
return options.map(option => {
return (
<React.Fragment key={option.key}>
<input
type='radio'
id={option.id}
{...field}
value={option.value}
checked={field.value === option.value}
/>
<label htmlFor={option.id}>{option.key}</label>
</React.Fragment>
);
})
}
}
</Field>
</div>
);
};
export default RadioButton;
Then put the reusable RadioButton Component in the Main.js wherever you want the radio button input to render.
The result UI will be 3 radio buttons with values "value 1", "value 2" and "value 3".
You can check out this awesome youtube series to know more.
This can be done simply but using this code below. it worked for me:
You will need to import Formik from "formik"
<Formik
initialValues={{
email: '',
password:'',
gender:'',
}}
// validations
validationSchema={SignupSchema}
onSubmit={values => { console.log(values); }}
>
{(formik) => (
<Form onSubmit={formik.handleSubmit}>
//Your Other inputs........
<div className="custom-control">
<input
id="male"
type="radio"
value="male"
name='gender'
onChange={formik.handleChange}
defaultChecked={formik.values.gender=== "male"}
/>
<label
className="custom-control-label"
htmlFor="male"
>
Male
</label>
</div>
<div className="custom-control">
<input
id="female"
type="radio"
value="female"
name='gender'
onChange={formik.handleChange}
defaultChecked={formik.values.gender=== "female"}
/>
<label
className="custom-control-label"
htmlFor="female"
>
Female
</label>
</div>
//Your Other inputs......
<button type="submit">Submit</button>
</Form>
)}
</Formik>

Resources