I have a form wizard that I am trying to validate each screen when they hit the next button. I am using react-hook-form, yup and chakra-ui-steps.
My scheme is as such
const patientDetailsSchema = yup.object({
firstName: yup.string().required().nullable(),
lastName: yup.string().required().nullable(),
email: yup.string().email().required().nullable(),
gender: yup.string().required().nullable(),
mobilePhone: yup
.string()
.required()
.matches(phoneRegExp, "Phone number is not valid")
.nullable(),
dateOfBirth: yup.string().required().nullable()
});
const insuranceDetails = yup.object({
insurance: yup.string().required().nullable(),
})
My component is as follow
const AppointmentsModal = (props: AppointmentsModalProps) => {
const { isOpen, onClose } = props;
const { nextStep, prevStep, setStep, reset, activeStep } = useSteps({
initialStep: 1,
});
const {
control,
handleSubmit,
register,
resetField,
formState: { errors, isValid, touchedFields, dirtyFields },
getValues,
trigger,
setError,
} = useForm({
defaultValues: {
firstName: null,
lastName: null,
email: null,
dateOfBirth: null,
mobilePhone: null,
gender: null,
notes: null,
insurance: null,
insuranceSelect: null,
insuranceGroup: null,
insuranceNumber: null,
memberId: null,
},
mode: "onChange",
resolver: yupResolver(patientDetailsSchema),
});
return ( rest of the code)
What I am trying to figure out is how do I I add different schemas so that it validates at each screen.
any ideas as to how to combine different yup schemas to be trigger at different points in the wizard?
Related
hello i have a little problem
that is, I will do a validation, but I want to make validations according to the member type, so if it is corporate, the tax number will be mandatory, but the phone number not
if it is individual it will be the opposite
a phone validations when the value is false
if value is true then only tax validations
setup() {
const value = ref(false);
const validationSchema = Yup.object().shape({
phone: Yup.string().trim().required().label("Phone"),
tax: Yup.string().trim().required().label("Tax"),
});
const { handleSubmit } = useForm({ validationSchema });
const submit = handleSubmit(async (values) => {
console.log("personName:", values);
});
return {
validationSchema,
submit,
value,
};
},
Add memberType to the validation then you can do something like this:
const validationSchema = Yup.object().shape({
memberType: Yup.string().required(),
phone: Yup
.string()
.trim()
.label("Phone")
.when("memberType", {
is: "individual",
then: Yup.string().required("Must enter phone number")
}),
tax: Yup
.string()
.trim()
.label("Tax")
.when("memberType", {
is: "corporate",
then: Yup.string().required("Must enter tax number")
}),
});
I have this yup which is works:
const exceptionSchema = yup.object().shape({
exceptionRule: yup.object().shape({
exceptionCondition: yup.object().shape({
exceptionCount: yup.string().required('Exception_Count_Required')
}),
selectedExceptions: yup
.array()
.ensure()
.min(1, 'Validate_ExceptionsAssigned')
})
});
But I have to validate this subobject selectedExceptions when some other property is equals to 1:
and this doesnt work:
const exceptionSchema = yup.object().shape({
exceptionRule: yup.object().shape({
exceptionCondition: yup.object().shape({
exceptionCount: yup.string().required('Exception_Count_Required')
}),
selectedExceptions: yup
.array()
.ensure()
// .min(1, 'Validate_ExceptionsAssigned')
.when('type', {
is: 1,
then: yup
.array()
.ensure()
.min(1, 'Validate_ExceptionsAssigned')
})
})
});
this is mine model, and I think because the type proeprty is not within this object exceptionRule then yup validation does not take into consideration this .when() clause.
Model:
const newRule = () => ({
type: '',
exceptionRule: {
exceptionCondition: {
exceptionCount: '1',
condition: 1,
frequency: 1
},
selectedExceptions: [],
}
});
How to get this type from above, outside my inner object?
How can I debug this when('type') to be sure what value does it have?
I'm new to Mongoose and NodeJS and I'm building a ticket management system where logged in users can fill up a form to create a ticket. It has two fields (title and description) but when submitting it, I'd like to also add some user's data to the form data object.
On the front end I'm using React with Formik to handle the form.
My user data object is stored in local storage using JWT.
Here are my current models for the ticket and for the user:
//ticket.model.js
module.exports = (mongoose) => {
const Ticket = mongoose.model(
'ticket',
mongoose.Schema(
{
title: String,
description: String,
},
{ timestamps: true }
)
);
return Ticket;
};
//user.model.js
const User = mongoose.model(
'User',
new mongoose.Schema({
firstName: String,
lastName: String,
email: String,
password: String,
roles: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Role',
},
],
})
);
module.exports = User;
Here is the Formik function:
const formik = useFormik({
initialValues: {
title: '',
description: '',
},
validationSchema,
validateOnBlur: false,
validateOnChange: false,
onSubmit: (data) => {
TicketService.create(data).then(() => {
navigate('/home');
window.location.reload();
});
},
});
Ideally, when the ticket is being created I'd like to query Mongoose with user's ObjectId to retrieve his firstName and lastName. If it's too complicated I don't mind just adding the user's names to the form data using JSON.parse(localStorage.getItem('user')). Or if you have better practices, please let me know.
Thank you!
Never mind, my formik object was actually missing the user element (see below).
const formik = useFormik({
initialValues: {
title: '',
description: '',
authorId: JSON.parse(localStorage.getItem('user')).id,
authorName: `${JSON.parse(localStorage.getItem('user')).firstName} ${
JSON.parse(localStorage.getItem('user')).lastName
}`,
},
validationSchema,
validateOnBlur: false,
validateOnChange: false,
onSubmit: (data) => {
console.log(data);
TicketService.create(data).then(() => {
navigate('/home');
window.location.reload();
});
},
});
From there I just updated my model and controller accordingly:
module.exports = (mongoose) => {
const Ticket = mongoose.model(
'ticket',
mongoose.Schema(
{
title: String,
description: String,
authorId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
authorName: String,
},
{ timestamps: true }
)
);
return Ticket;
};
I have a React state object called formData with user checkout shipping data and inside formData there is another object called billingAdress which contains user billing data.
state = {
user: null,
formData: {
name: null,
company: null,
adressOne: null,
adressTwo: null,
town: null,
postcode: null,
country: null,
phone: null,
isBillingAdress: false,
billingAdress: {
name: null,
company: null,
adressOne: null,
adressTwo: null,
town: null,
postcode: null,
country: null,
phone: null,
}}
There is onChange function on input
<label>Full Name:</label>
<input
name="name"
onChange={this.handleBillingChange}
value={this.state.formData.billingAdress.name}
/>
Function looks like this
handleBillingChange = event => {
const formData = { ...this.state.formData, billingAdress: {[event.target.name]: event.target.value }}
const errors = { ...this.state.errors, [event.target.name]: '' }
this.setState({ formData, errors})
}
Im trying to store whole billingAdress object inside of formData object, when I start typing in the first billing adress input, it works well, but when i start typing in a second input, first input disappear from a state.
The problem lies in your handleBillingChange function.
Try this in order to keep the current state of formData.billingAdress when changing one property.
const handleBillingChange = event => {
const formData = {
...this.state.formData,
billingAdress: {
...this.state.formData.billingAdress,
[event.target.name]: event.target.value
}
}
const errors = { ...this.state.errors, [event.target.name]: '' }
this.setState({ formData, errors})
}
const schema = Joi.object().keys({
Id: Joi.number().required(),
CustomerName: Joi.string()
.trim()
.required()
.when('$isInValidCustomer', {
is: true,
then: //Add some error in existing error block,
}),
BankName: Joi.string().trim(),
});
const custDetail = {
Id: 2,
CustomerName: 'xyz'
BankName: ''
};
const schemaOptions = {
abortEarly: false,
context: {
isInValidCustomer: true,
},
};
const valError = schema.validate(custDetail, schemaOptions);
So, now when I validate 'custDetail' object I want following 2 errors:
- CustomerName error because 'isInValidCustomer' is true
- BankName is required
I am not able to append error for CustomerName in existing error object. If I use '.error()' then just get single error corresponding to 'CustomerName' else just getting error for BankName.
Any help is really appreciated.
This can be achieved using custom function.
const schema = Joi.object().keys({
Id: Joi.number().required(),
CustomerName: Joi.string()
.trim()
.required()
.when('$isInValidCustomer', {
is: true,
then: Joi.any().custom(() => {
throw new Error('Invalid Customer');
}),
}),
BankName: Joi.string().trim(),
});