I have a Field in a Formik which needs a dynamic validation Schema: When a user selects a payment token, the minimum payment value must be dynamically changed for another input field. I used a state value and the "onChange" listener from the Field, and it works, except the displayed value
{token.symbol}
is not rendered any more.
As if overriding the "onChange()" field method had deactivated the Formik selection of this field.
Any idea what's happening ?
My code:
import { ErrorMessage, Field, Form, Formik } from 'formik';
import { SetStateAction, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import * as Yup from 'yup';
import SubmitButton from './SubmitButton';
import useAllowedTokens from '../../hooks/useAllowedTokens';
interface IFormValues {
rateToken: string;
rateAmount: number;
}
const initialValues: IFormValues = {
rateToken: '',
rateAmount: 0,
};
function ServiceForm() {
const navigate = useNavigate();
const allowedTokenList = useAllowedTokens();
const [selectedToken, setSelectedToken] = useState('');
const validationSchema = Yup.object({
rateToken: Yup.string().required('Please select a payment token'),
rateAmount: Yup.number()
.required('Please provide an amount for your service')
.when('rateToken', {
is: (rateToken: string) => rateToken !== '',
then: schema =>
schema.moreThan(
allowedTokenList.find(token => token.address === selectedToken)
?.minimumTransactionAmount || 0,
`Amount must be greater than ${
allowedTokenList.find(token => token.address === selectedToken)
?.minimumTransactionAmount || 0
}`,
),
}),
});
// const onSubmit = async (values: IFormValues) => {
// <...>
// }
return (
<Formik initialValues={initialValues} onSubmit={onSubmit} validationSchema={validationSchema}>
{({ isSubmitting }) => (
<Form>
<div className='grid grid-cols-1 gap-6 border border-gray-200 rounded-md p-8'>
<div className='flex'>
<label className='block flex-1 mr-4'>
<span className='text-gray-700'>Amount</span>
<Field
type='number'
id='rateAmount'
name='rateAmount'
className='mt-1 mb-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50'
placeholder=''
/>
<span className='text-red-500 mt-2'>
<ErrorMessage name='rateAmount' />
</span>
</label>
<label className='block'>
<span className='text-gray-700'>Token</span>
<Field
component='select'
id='rateToken'
name='rateToken'
className='mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50'
placeholder=''
onChange={(event: { target: { value: SetStateAction<string> } }) => {
setSelectedToken(event.target.value);
}}>
<option value=''>Select a token</option>
{allowedTokenList.map((token, index) => (
<option key={index} value={token.address}>
{token.symbol}
</option>
))}
</Field>
<span className='text-red-500'>
<ErrorMessage name='rateToken' />
</span>
</label>
</div>
<SubmitButton isSubmitting={isSubmitting} label='Post' />
</div>
</Form>
)}
</Formik>
);
}
export default ServiceForm;
Tried: Overriding onChange() field method
Expected: The selected <option>'s value (token) should be updated in the form's input data, but is not.