Validation 2 fields with yup and formik - reactjs

This is my default value:
const defaultValues = {
busi_day: [],
busi_start_time: '09:00',
busi_end_time: '17:00',
};
This is my 2 fields:
<FastField type="time" className="start-time" name="busi_start_time" value={values.busi_start_time} />
<FastField type="time" className="start-time" name="busi_end_time" value={values.busi_end_time} />
This is my validatio using Yup:
const validationSchema = Yup.object().shape({
busi_start_time: Yup.string()
.required(),
busi_end_time: Yup.string()
.required(),
});
Now, I want to validate that the busi_end_time must be after the busi_start_time. For example:
{busi_start_time: '09:00' busi_end_time: '17:00'} is valid but {busi_start_time: '14:00' busi_end_time: '08:00'} is not valid. How I can do that?

Use moment.js library and code below:
Yup.object().shape({
busi_start_time: Yup.string().required("Start time cannot be empty"),
busi_end_time: Yup.string()
.required("end time cannot be empty")
.test("is-greater", "End time should be greater", function (value) {
const { busi_start_time} = this.parent;
return moment(value, "HH:mm").isSameOrAfter(moment(busi_start_time, "HH:mm"));
})
});

Related

react-hook-form + yup validation field value

I`ve got this yup schema:
`const ModalEditCard = () => {
const validationSchema = Yup.object().shape({
title: Yup.string()
.required("Поле обязательно для заполнения")
.max(50, "Заголовок не более 50 символов")
});`
React-hook-form options:
const {
register,
handleSubmit,
formState: { errors, isValid }
} = useForm<UserSubmitForm>({
resolver: yupResolver(validationSchema),
mode: "onSubmit",
reValidateMode: "onChange",
});
and this textarea:
` <textarea
{...register(name)}
rows={1}
className="modal__textArea"
placeholder={placeholder}
/>`
I whant to show how mach symbols user has to write. Example I have max 50 symbols for textarea. If I write hello, under field i want to see "45". And it`s should be just message. Not validate
I had custom hook for count symbols. But i think, Yup could help me

React formik mui checkbox inquiry

I am having great difficulty trying to get the error text to appear below my mui checkbox when I yarn dev my signup form. Below is a snippet of the jsx code I used.
``` <FormControlLabel
control={<Checkbox checked={formik.values.termsAndConditions}/>}
label={
<TermsTypography>
I accept the terms and conditions
</TermsTypography>
}
name="termsAndConditions"
onChange={formik.handleChange}
/>```
ValidationSchema:
```const validationSchema = Yup.object({
username: Yup
.string()
.required('Username is required')
.min(8, 'Username should be a minimum of 8 characters in length')
.max(30, 'Username should not exceed 30 characters in length'),
email: Yup
.string()
.email('Enter a valid email')
.required('Email is required'),
password: Yup
.string()
.required('Password is required')
.matches(/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/, 'Password must have at least one letter and number and a minimum of 8 characters')
.min(8, 'Password should be of minimum 8 characters length')
.max(30, 'Password should not exceed 30 characters in length'),
confirmPassword: Yup
.string()
.oneOf([Yup.ref('password'), null], 'Passwords must match'),
termsAndConditions: Yup
.bool()
.oneOf([true], 'You must accept the terms and conditions')
});```
const formik:
```const formik = useFormik({
initialValues: {
username: '',
email: '',
password: '',
confirmPassword: '',
termsAndConditions: false
},
validationSchema: validationSchema,
onSubmit: (values) => {
console.log(values);
setIsLoading(true);
},
});```
I don't think there is an error in my validation Schema or in my formik. From what I have gathered elsewhere on stackoverflow the checkbox is rather tricky. Perhaps the way I am using label for my FormControlLabel is what is causing the issue? I also have my formik and Yup imports imported properly or else my other jsx elements like user name and password would not be showing any error handling. So what am I doing wrong here?

how can I check if the password matches with yup

I want to use oneOf but it doesnt work. I want to check If the password and password-Repeat matches. In nodejs it works, but in react native it doesnt work. All errors are shown except password-Repeat. Why?
const registerSchema = yup.object().shape({
fullName: yup.string()
.required('Your name is required.')
.min(4)
.max(40),
email: yup.string()
.required()
.min(6)
.max(255)
.email(),
password: yup.string()
.required()
.min(7)
.max(255),
passwordRepeat: yup.string()
.oneOf([yup.ref('password'), null], 'Password does not match')
});
all my TextInput has values and onChangeText and onBlur and all fields work fine except password repeat
Try this way
Yup.object().shape({
password: Yup.string().required("Required"),
passwordRepeat: Yup.string()
.required("Required")
.when('password', (password, schema) => {
return schema.test({
test: (passwordRepeat) => password === passwordRepeat,
message: 'Password does not match',
});
}),
});

Yup validation for loginID with dynamic data type(either email or phone number)

I am trying to implement login functionality using Formik and Yup. This is my current schema
let loginSchema = yup.object().shape({loginId:
yup
.string()
.email("That doesn't look like a valid email")
.required("This field is required."),password: yup.string().required("This field is required."),});
But my loginId can either be a phone number or email. So, how do i add the validation based on the type of field that has been entered in the form. If its an email, trigger validation for email or if its phone number, i want to validate it against a regex.
Input field that accepts both email and phone:
const LoginSchema = yup.object().shape({
email_or_phone: yup.string()
.required('Email / Phone is required')
.test('email_or_phone', 'Email / Phone is invalid', (value) => {
return validateEmail(value) || validatePhone(parseInt(value ?? '0'));
}),
password: yup.string().required()
});
const validateEmail = (email: string | undefined) => {
return yup.string().email().isValidSync(email)
};
const validatePhone = (phone: number | undefined) => {
return yup.number().integer().positive().test(
(phone) => {
return (phone && phone.toString().length >= 8 && phone.toString().length <= 14) ? true : false;
}
).isValidSync(phone);
};
Solved email and PhoneNumber Validation
const loginValidationSchema = Yup.object({
email: Yup.string().when("isEmail", {
is: '1',
then: Yup.string()
.email("Please enter valid email")
.required("email cannot be empty"),
otherwise: Yup.string()
.required("phonenumber cannot be empty")
.min(6, 'phonenumber must be at least 6 char'),
}),
password: Yup.string()
.required("Password cannot be empty")
.min(6, 'Password must be at least 6 char'),
});
<Formik
validationSchema={loginValidationSchema}
initialValues={{ isEmail: 0, email: '', password: '' }}
onSubmit={}
>
{({ handleChange, handleBlur, handleSubmit, values, errors,
touched }) => (
<View>
<TextInput
placeholder="ramchandran2897#gmail.com"
onChangeText={(event)=>{
handleChange("email")(event)
if(Number(values.phonenumberOrEmail)){
handleChange("isEmail")('0')
}else{
handleChange("isEmail")('1')
}
}}
onBlur={handleBlur('email')}
value={values.email}
keyBoardType="email-address"
autoFocus={false}
returnKeyType='next'
returnKeyLabel='>'
onSubmitEditing={() => passwordRef.current?.focus()}
error={errors.email}
touched={touched.email}
/>
<TextInput
placeholder="****"
placeholderTextColor={Colors.darkLight}
onChangeText={handleChange('password')}
onBlur={handleBlur('password')}
value={values.password}
secureTextEntry={hidePassword}
isPassword={true}
hidePassword={hidePassword}
setHidePassword={setHidePassword}
min={6}
autoCapitalize='none'
keyboardAppearance='dark'
onSubmitEditing={handleSubmit}
ref={passwordRef}
error={errors.password}
touched={touched.password}
/>
<TextInput
onChangeText={handleChange('isEmail')}
keyBoardType='none'
/>
</View>
)}
</Formik>
If you want to dynamically validate your fields, use when for the validationSchema.
An example from the documentation.
let schema = object({
isBig: boolean(),
count: number()
.when('isBig', {
is: true, // alternatively: (val) => val == true
then: yup.number().min(5),
otherwise: yup.number().min(0),
})
.when('$other', (other, schema) => (other === 4 ? schema.max(6) : schema)),
});
So in your case you have to craft your is statement to decide whether it is an email of a phone number, then you can attach validation accordingly.
I didn't work with formik but face the same situation as you face here. I was working with Form Hook. Maybe somehow it will help you or someone.
First of all, add a hidden input after your main input in which the user will add phone or email. On change of that main input, you have to check that if this string contains '#' or not. If it contains # then make a state and update state with true like this.
const onChangeEmailOrPhone = (event) => {
let email = event.target.value.includes('#');
if (email) {
setIsEmail(true);
} else {
setIsEmail(false);
}
};
and set this state value to the hidden input just like this
<TextField
type="hidden"
name="isEmailValue"
inputRef={register}
value={isEmail}
/>
Following should be your validation schema to check weather isEmailValue is true or not, If true then you have to validate for email otherwise for the phone just like this.
let loginSchema = yup.object().shape({
emailOrPhone: yup.string().when('isEmailValue', {
is: 'true',
then: yup
.string()
.email('Please enter valid email')
.required('This field is required'),
otherwise: yup
.string()
.matches(phoneRegex, 'Please enter valid phone number')
.required('This field is required'),
})});
Following is phoneRegex for your help
const phoneRegex = /^(\+?\d{0,4})?\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{4}\)?)?$/;

schedules[0].timings[0].startTime must be a `string` type, but the final value was: `null` - getting this value when field remains empty

const validationSchema = () => {
return Yup.lazy(values => {
return Yup.object().shape({
name: Yup.string().required("This field is required"),
streetAddress: Yup.string().required("This field is required"),
city: Yup.string().required("This field is required"),
state: Yup.string().required("This field is required"),
zipCode: Yup.string().required("This field is required"),
country: Yup.string().required("This field is required"),
phone: Yup.string().required("This field is required"),
// consultingCharge: Yup.string().required("This field is required"),
schedules: Yup.array().of(
Yup.object().shape({
available: Yup.boolean(),
timings: Yup.array().of(
Yup.object().shape({
startTime: Yup
.string()
.when('available', {
is: true,
then: Yup.string().required('Field is required'),
otherwise: Yup.string()
}),
endTime: Yup
.string()
.when('available', {
is: true,
then: Yup.string().required('Field is required'),
otherwise: Yup.string()
})
.test("", "End time must be after Start time" , function(values){
return this.parent.startTime < values;
}),
})
)
})
)
})
})
}
Facing the below error:
schedules[0].timings[0].endTime must be a string type, but the final value was: null. If "null" is intended as an empty value be sure to mark the schema as .nullable()
When leave the field blank for start time and end time.
I'm not sure if this is related to the schema, I can imagine you use it in combination with formik or some other form library? It looks like your state that is getting validated against that schema is providing a null value for the endTime property. Can you verify it's not an issue with the state object itself? Could it be that you have an input field which is empty and the onChange handler is setting the value from the state to null instead of ""? :)

Resources