I'm using formik with yup and using Yup.addMethod().
I'm using React 16.5
Example:
validationSchema: Yup.object().shape({
file:Yup.addMethod(Yup.string, 'file',(file)=>{
console.log(file);
return "This is not a valid file.";
})
}),
I'm getting error:
TypeError: Cannot read property 'length' of undefined
I鈥檓 not sure this is a Formik error. Can you please provide a codesandbox and complete the issue template?
@jaredpalmer Thanks for reply.
Here is my codesandbox URL: https://codesandbox.io/s/wz6y0qwrm8
When you will upload any file this will through the error.
If you will comment the following part you will not see on change error:
file: Yup.addMethod(Yup.array, "file", file => {
console.log(file);
return "This is not a valid file.";
})
I'm also getting this error; I'm using yup, but not using .addMethod.
updated yup from 0.24.1 to latest and now getting this error
@raq929 , @nathanhannig
Make sure the specific property of initialValues you're checking inside the validationSchema is also present inside the validationSchema.
See this answer for an example: https://stackoverflow.com/questions/49394391/conditional-validation-in-yup?rq=1
What @fullmetalsheep wrote helped me in one case. Other case was that my custom string().test() method had an error inside and crashed silently resulting in this message. See inside all your custom test() methods if they do not crash (In my case I didn't handle undefined value passed to it)
Hey @fullmetalsheep I am getting this error while using Formal & Yup in combination.
const schema = yup.object().shape({
Username: yup.string().required(),
Email: yup
.string()
.email('Invalid Email Address')
.required(),
Password: yup
.string()
.min(4)
.max(32)
.matches('^(?=.*[a-z])(?=.*[A-Z])(?=.*d)[a-zA-Zd]$')
.required(),
'Confirm Password': yup
.string()
.oneOf([yup.ref('Password'), null], "Passwords don't match")
.required(),
})
const initialValues = {
Username: '',
Email: '',
Password: '',
'Confirm Password': '',
}
const Field = ({ placeholder, error, ...props }) => (
<>
<Text style={styles.space}>{placeholder}</Text>
<Input {...props} />
{error && (
<Text style={[styles.space, error && styles.error]}>{error}</Text>
)}
</>
)
function App() {
const formal = useFormal(initialValues, {
schema,
onSubmit: values => {
Alert.alert(JSON.stringify(values))
},
})
return (
<SafeAreaView>
<View style={styles.space}>
<Text h1>Formal</Text>
<Field {...formal.getFieldProps('Username')} placeholder="Username" />
<Field {...formal.getFieldProps('Email')} placeholder="Email" />
<Field
{...formal.getFieldProps('Password')}
placeholder="Password"
secureTextEntry
/>
<Field
{...formal.getFieldProps('Confirm Password')}
placeholder="Confirm Password"
secureTextEntry
/>
<Button
style={styles.space}
{...formal.getSubmitButtonProps()}
title="Submit"
type="outline"
/>
</View>
</SafeAreaView>
)
}
And the values are present in both my schema & initialValues properties. The weird part is it was working yesterday just fine.
Anything missing?
@deadcoder0904 maybe try replacing 'Confirm Password' with something like confirmPass? I'm currently travelling and have no method of testing code sorry :(
No, it does not work. I was earlier using confirmPass but then changed to Confirm Password when it was working. Thanks though & no worries, safe travels :)
So this happens when you has an error in your custom validation function
In my case the error was
Cannot read property 'replace' of undefined
So yup will throw here https://github.com/jaredpalmer/formik/blob/c5243947fcf21cd873dd86b57689a30ffc46eab8/src/Formik.tsx#L258
if there is real validation errors or if there is an error in the validation function
so this will throw https://github.com/jaredpalmer/formik/blob/c5243947fcf21cd873dd86b57689a30ffc46eab8/src/Formik.tsx#L683
We can check if yupError has inner, and if not, we should show the error to end user
what do you guys think of this solution?
Hey, @sibelius I actually found a workaround solution to it. I removed the .matches('^(?=.*[a-z])(?=.*[A-Z])(?=.*d)[a-zA-Zd]$') thing & it worked.
The full working code 馃憠https://github.com/deadcoder0904/expo-formal/blob/master/App.js
For those coming after me, what I realized is that the yup test method actually doesn't accept an arrow function.
Doesn't work:
confirmPassword: Yup.string()
.min(6, 'Password must be at least 6 characters')
.test('passwords-match', 'Password Confirmation must match', value => {
if (!value) {
return false;
}
return this.parent.password === value;
})
.required('Password Confirmation is required.')
Works:
confirmPassword: Yup.string()
.min(6, 'Password must be at least 6 characters')
.test('passwords-match', 'Password Confirmation must match', function(value) {
if (!value) {
return false;
}
return this.parent.password === value;
})
.required('Password Confirmation is required.')
@tannerhallman actually, it's not that it doesnt accept arrow functions. It's because you're referencing this inside of your arrow function. this does NOT have the proper Yup context so it errors out.
@deadcoder0904 the error could be coming from the regex that you used to validate password, instead of using quote around the regex ('{regex}') trying using forward slash (/{regex}/)
before:
Password: yup.string().matches('^(?=.*[a-z])(?=.*[A-Z])(?=.*d)[a-zA-Zd]$').required(),
after:
Password: yup.string().matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*d)[a-zA-Zd]$/).required(),
see the doc for reference: https://github.com/jquense/yup#stringmatchesregex-regex-message-string--function-schema
I had the same problem, but in a test function:
name: Yup.string()
.required('Required')
.test(
'is-unique',
'Must be unique(case-insensitive)',
function test(value) {
const { existingNames = [] } = this.parent;
return !existingNames.includes(value.toLowerCase())
}
)
to fix this, I had to test for 'value' before calling 'toLowerCase'. I expected this function wouldn't be hit because of the 'required', but I was wrong. This fixed it:
name: Yup.string()
.required('Required')
.test(
'is-unique',
'Must be unique(case-insensitive)',
function test(value) {
const { existingNames = [] } = this.parent;
return value && !existingNames.includes(value.toLowerCase())
}
)
just adding ? to value or make sure its not undefined
password: yup
.string()
.test(
'password',
'Password must be at least 8 characters',
(value: string) => value?.length >= 8
)
.required('Password is required!')
Future me has come across a situation similar to this and I have re-read the Yup docs (I know I know, why?!).
Newer versions of Yup have added some clarity. See this section.
Specifically:
test functions are called with a special context, or this value, that exposes some useful metadata and functions. Older versions just expose the this context using function (), not arrow-func, but now it's exposed too as a second argument of the test functions. It's allow you decide which approach you prefer.
Meaning that you can now use the newer function signature of 2 arguments which would involve adding the context to replace this.
confirmPassword: Yup.string()
.min(6, 'Password must be at least 6 characters')
.test('passwords-match', 'Password Confirmation must match',
(value, context) => {
if (!value) {
return false;
}
return context.parent.password === value;
})
.required('Password Confirmation is required.')
Note: I haven't tried this to verify it actually works, but it seems that this explanation was right. Cheers @sgnl
@tannerhallman actually, it's not that it doesnt accept arrow functions. It's because you're referencing
thisinside of your arrow function.thisdoes NOT have the proper Yup context so it errors out.
Most helpful comment
For those coming after me, what I realized is that the yup test method actually doesn't accept an arrow function.
Doesn't work:
Works: