How to validate material-ui select with Formik and Yup - reactjs

I just started with Yup and Formik. I have a pretty basic form. The TextFields that I have are working just fine in terms of validation with Yup. The select is what I am having trouble with. I've been trying to get it to be required just like my text fields. I have been googling for awhile but I haven't found anything that has helped thus far.
I tried making my own validation that happened onBlur and that worked, but when it came to just trying to save without filling any values in it failed. The text fields would show required, but the select wouldn't show anything. You could fill out the text fields and try to save again. Doing that would show the required message for the select now because it could submit. From what I can tell formik's submit doesn't happen until all the Yup required fields are good to go. I will post what I am trying below, any help would be appreciated.
If I comment out the Yup validation requirements and log out the values on submit, the selected value does show up, so that seems to be working at least. Just can't figure out how to validate it.
import React, { useEffect, useState } from "react";
import Button from '#material-ui/core/Button'
import Grid from '#material-ui/core/Grid'
import { TextField, Select } from "formik-material-ui";
import { Formik, Form, Field } from "formik";
import * as Yup from "yup";
import MenuItem from "#material-ui/core/MenuItem"
const Validation = Yup.object().shape({
FirstName: Yup.string().required("Required"),
LastName: Yup.string().required("Required"),
Gender: Yup.string().required("Required"),
});
<Formik
onSubmit={(values) => {
SaveSettings(values)
}}
enableReinitialize
validateOnChange={false}
initialValues={data}
validationSchema={Validation}
>
{({ submitForm, handleChange }) => (
<Form>
<Field
component={Select}
name="Gender"
variant="outlined"
label="Gender"
className={classes.formControl}
onChange={e => handleChange(e)} >
<MenuItem value="Male">Male</MenuItem>
<MenuItem value="Female">Female</MenuItem>
</Field>
<Grid item>
<Field
disabled={false}
component={TextField}
data-id="FirstName"
variant="outlined"
label="First Name"
className={classes.formControl}
name="FirstName" />
</Grid>
<Grid item>
<Field
disabled={false}
component={TextField}
data-id="LastName"
variant="outlined"
label="Last Name"
className={classes.formControl}
name="LastName" />
</Grid>
<Grid item>
<Button type="button" variant="contained" onClick={submitForm}>Save settings</Button>
</Grid>
</Form>
)}
</Formik>

Related

Form validation using regex is not working TextField MUI React

I am trying to add a regex pattern in inputProps for validation of Textfield and required but both not working, on click of next the empty or wrong input is also getting entered.
<TextField
id="outlined-basic"
name="s_firstName"
label="First Name"
variant="outlined"
defaultValue={user.s_firstName}
onChange={handleChange}
inputProps={{pattern: "[a-z]"}
required />
Please can you help what wrong is there validation not working?
Your code seems fine, and required is working if you submit the form. It shows which field is required with a mark on the label.
In material ui,
required bool
If true, the label is displayed as required and the input element is required.
You will notice a warning popup as you type in your input.
For validation, you could write your own function with onChange.
const handleValidation = (e) => {
const reg = new RegExp("[a-z]");
setValid(reg.test(e.target.value));
setValue(e.target.value);
};
With the error prop of <Textfield>, you could do something like this,
<TextField
id="outlined-basic"
name="s_firstName"
label="First Name"
variant="outlined"
value={value}
onChange={(e) => handleValidation(e)}
error={!valid}
required={true}
/>
Check out this demo for code of two scenarios.
If you want to show error message then use "helperText"
<TextField
error={value=== ""}
helperText={value=== "" ? 'Please enter a value!' : ' '}
>

Joi validation for select,date,checkbox in react typescript form

I am using joi validation for validating inputs in react project. String inputs working fine but select,date,checkbox inputs not working.
Below code for date picker and typehead select option method. here if we submit empty date and empty select option error is throwing. after choosing values errors not fading.
<DatePicker
type="date"
id={"initialDate"}
value={getSelectedDate(tripData.initialPaymentDate)}
format={dateFormat}
clearIcon={null}
required={true}
showLeadingZeros={true}
onChange={(date: any) => {
setTripData({
...tripData,
initialPaymentDate: date,
});
}}
defaultValue={tripData.initialPaymentDate}
{...register("initialDate")}
/>
<Typeahead
inputProps={{ autoComplete: "nope" }}
id="airlineData"
//onChange={(data) => {
// setTravelSuppliers({...travelSuppliers, airline: data });
//{...register("airlineData")}
// }}
options={airLinesData}
defaultSelected={travelSuppliers["airline"]}
// defaultValue={travelSuppliers["airline"]}
{...register("airlineData")}
/>
Here checkbox code is available, checkbox no errors showing.
<input
className="form-check-input"
type="checkbox"
id="acknowledge"
defaultValue='false'
{...register("acknowledge")}
/>

Form validation and error messages not working

I'm currently working on several forms for an app and chose to use Material UI and React Hook Forms to build them. The basic functions are working, which means I can only proceed when all required inputs are filled and I'm getting the desired data.
Unfortunately I'm not able to use the form validation or display of error messages that comes with React Hook Form. It is still using the Material UI validation, even though I followed along to the documentation as close as possible.
Here's what I want to be able to do:
define the min and max length of an input
enter RegEx patterns for password inputs
show the neat looking error messages of React Hook Form
Some of the logic is working, some is not. Can you help me figure out why? Thank you in advance!
import React from 'react';
import { useForm, Controller } from 'react-hook-form';
import { Link } from 'react-router-dom';
// COMPONENTS
import Button from '../01-atoms/inputs/Button';
import Textfield from '../01-atoms/inputs/Textfield';
// MATERIAL UI - CORE
import Fade from '#material-ui/core/Fade';
import Grid from '#material-ui/core/Grid';
import InputAdornment from '#material-ui/core/InputAdornment';
import Typography from '#material-ui/core/Typography';
import Paper from '#material-ui/core/Paper';
// MATERIAL UI - ICONS
import LockSharpIcon from '#material-ui/icons/LockSharp';
import PersonAddSharpIcon from '#material-ui/icons/PersonAddSharp';
export default function SignUp({ i18n, submitSignUpData }) {
const { register, handleSubmit, control, errors } = useForm();
return (
<Grid item xs={12} sm={6} md={3}>
<Fade in>
<Paper elevation={3}>
<Typography align='center' gutterBottom variant='h5'>
{i18n.sign_up.page_title}
</Typography>
<form onSubmit={handleSubmit(submitSignUpData)}>
<Grid container spacing={1}>
<Grid item xs={12}>
<Controller
// This is not working:
rules={register({
required: true,
minLength: 8,
})}
// But this is:
required
as={Textfield}
name='newPassword'
control={control}
defaultValue=''
fullWidth
label={i18n.login.password_placeholder}
variant='outlined'
type='password'
InputProps={{
endAdornment: (
<InputAdornment position='end'>
<LockSharpIcon />
</InputAdornment>
),
}}
/>
{errors.newPassword && 'Your input is required!'}
</Grid>
<Grid item xs={12}>
<Button
fullWidth
content={i18n.sign_up.get_started_button}
variant='contained'
color='secondary'
type='submit'
endIcon={<PersonAddSharpIcon />}
/>
</Grid>
</Grid>
</form>
<Link to='/log-in'>
<Typography>{i18n.login.login_button}</Typography>
</Link>
</Paper>
</Fade>
</Grid>
);
}
Instead of using controller why don't you use TextField of Material UI. I have something like this in my code.
<TextField
name="newPassword"
label="Password"
inputRef={register({ required: true, minLength: 8 })}
defaultValue=''
/>
{
errors.newPassword &&
<ErrorText>
{errors.newPassword.type === "required" ?
'Password is required.' :
`Min character limit for Password is 8.`}
</ErrorText>
}

How to use react-hook-form with ant design or material UI

I'm trying to use react-hook-form library to validate a form. When I render view using ant design or material UI, it does not work correctly.
<Input name="firstName" ref={register({ required: true })} />
{errors.firstName && 'First name is required'}
Some warning happened: "Missing name at.....".
For Material-UI you can pass register through the TextField component prop inputRef (I'm also using Yup for validation schemas)
import React, { useState } from 'react';
import { Button, TextField } from '#material-ui/core';
import useForm from 'react-hook-form';
import { object, string } from 'yup';
const Form: React.FC = () => {
const schema = object().shape({
username: string().required('Username is required'),
password: string().required('Password is required'),
});
const { register, handleSubmit, errors } = useForm({ validationSchema: schema });
const onSubmit = (data: any) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<TextField
name="username"
error={!!errors.username}
label="Username"
helperText={errors.username ? errors.username.message : ''}
type="email"
inputRef={register}
fullWidth
/>
<TextField
name="password"
error={!!errors.password}
label="Password"
inputRef={register}
helperText={errors.password ? errors.password.message : ''}
type="password"
fullWidth
/>
<Button
color="primary"
type="submit"
variant="contained"
fullWidth
>
Submit
</Button>
</form>
);
};
react hook form author here. React Hook Form embrace uncontrolled components and native inputs, however it's hard to avoid working with external controlled component such as React-Select, AntD and Material-UI. So I have built a wrapper component to help you integrate easier.
https://github.com/react-hook-form/react-hook-form-input
Ok you may wonder what’s the point of doing this, and what are you gettin out from react hook form with controlled components? Firstly, you still benefit from our in build validation or schema validation at your choice. Secondary this will improve your app or form performance by isolating your input state update to itself, which means ur form root can be resulted with 0 re-render even with controlled component.
Here is codesandbox example:
https://codesandbox.io/s/react-hook-form-hookforminput-rzu9s
Hopefully those make sense and that extra component Which I have created helps you too.
On top this, i have also built a wrapper component to make things a bit easier:
import React from 'react';
import useForm from 'react-hook-form';
import { RHFInput } from 'react-hook-form-input';
import Select from 'react-select';
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
function App() {
const { handleSubmit, register, setValue, reset } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<RHFInput
as={<Select options={options} />}
rules={{ required: true }}
name="reactSelect"
register={register}
setValue={setValue}
/>
<button
type="button"
onClick={() => {
reset({
reactSelect: '',
});
}}
>
Reset Form
</button>
<button>submit</button>
</form>
);
}
https://github.com/react-hook-form/react-hook-form-input
update
React-hook-form v4, react-hook-form-input has been merged into the main repo and renamed to Controller.
https://react-hook-form.com/api#Controller
The latest advice for V4 is to use the built-in <Controller /> component (docs). You don't need to install the extra dependency of react-hook-form-input.
From the README.md of react-hook-form-input:
This component is now a part of React Hook Form V4, and renamed to Controller with much simpler API.
Example:
<Controller
as={<TextField />}
name="firstName"
control={control}
defaultValue=""
/>
Note that the #Bill, the author of the accepted answer, now also says that the answer is outdated and to "please use controller instead."
Using the inputRef should be enough to the TextField component and for any default value the react-hook-form (useForm) provide the defaultValue in case that you want to use some default value or material-ui has the defaultValue in their TextField API
const { register, handleSubmit, errors, watch } = useForm({ mode: 'onChange' });
<TextField
inputRef={register({ required: true })}
label="Email Address"
name="email"
type="email"
autoComplete="email"
onChange={handleUpdate}
error={errors.email}
helperText={errors.email && 'email required'}
/>
I've had 0 issues using the TextField inputRef approach that some others have mentioned.
<TextField
inputRef={register}
id="name"
name="name"
/>
I posted a full working version here: https://seanconnolly.dev/react-hook-form-material-ui

React-Quill with Formik is not updating props

I am using Formik and React-Quill in my form,
The value seems to be updating when i use <input> but when i plug-in <ReactQuill /> it's not.
Is there something wrong with the setup?
<Field
name="designation"
value={this.props.values.designation}
render={({ field /* _form */ }) => (
// <input {...field} placeholder="designation" />
<ReactQuill
{...field}
/>
)}
/>
For anybody who is still interested in the answer (like I was), you can find it here:
<Formik initialValues={{ designation: '' }}>
<Field name="designation">
{({ field }) => <ReactQuill value={field.value} onChange={field.onChange(field.name)} />}
</Field>
</Formik>
This helps match formik field to ReactQuill props.
I am using "setFieldValue" to update changes. This is working perfectly fine for dynamic Formik forms.
<ReactQuill
value={values.description}
onChange={v => setFieldValue('description', v)}
/>

Resources