Reputation: 11
I'm trying to validate a confirm password value with yup. Every solution I've looked through points to the same line of code but it's not working as intended.
I have a form with two inputs (password and confirm), and one submit button. The submit button is disabled until the formValues state passes validation. When the passwords don't match, the submit button is correctly disabled and when they match the button becomes active. However the error message does not go away.
Here is my yup schema:
import * as yup from 'yup'
export default yup.object().shape({
password: yup
.string()
.required("Password required"),
confirm: yup
.string()
.oneOf([yup.ref("password"), null], "Passwords don't match")
})
and here is the code for the form itself:
const initialValue = {
password: "",
confirm: ""
}
export default function Form() {
const [formValues, setFormValues] = useState(initialValue)
const [formErrors, setFormErrors] = useState(initialValue)
const [disabled, setDisabled] = useState(true)
const onChange = (e) => {
const {name, value} = e.target;
yup
.reach(formSchema, name)
.validate(value)
.then(() => {
setFormErrors({ ...formErrors, [name]: '' })
})
.catch((err) => {
setFormErrors({ ...formErrors, [name]: err.errors[0] })
})
setFormValues({...formValues, [name]: value })
}
const onSubmit = (e) => {
e.preventDefault()
}
useEffect(() => {
formSchema.isValid(formValues).then((valid) =>
setDisabled(!valid))
}, [formValues])
return (
<div>
<form onSubmit={onSubmit}>
<label>
Password:
<input
type="text"
name="password"
onChange={onChange}
value={formValues.password}
/>
</label>
<label>
Confirm Password:
<input
type="text"
name="confirm"
onChange={onChange}
value={formValues.confirm}
/>
</label>
<button type="submit" disabled={disabled}>
Submit
</button>
<div className="errors">
<div>{formErrors.password}</div>
<div>{formErrors.confirm}</div>
</div>
</form>
</div>
)
}
Upvotes: 0
Views: 5178
Reputation: 107
for typescript
changepassword: Yup.string().oneOf([Yup.ref('password')], 'Passwords must match').required('changepassword is required')
Upvotes: 0
Reputation: 31
I added required() at the end of the second password argument and it work.
confirm: yup.string().oneOf([yup.ref("password"), null], "Passwords don't match") }).required()
Upvotes: 2
Reputation: 476
First of all each time you checked old formValues
.
Second you should check touched fields for show error messages after user effected them.
I suggest to use Formik
.
But I fixed your code and also you can check it on this
import React, { useState, useEffect } from "react";
import * as yup from "yup";
const initialValue = {
password: "",
confirm: ""
};
export default function Form() {
const [formValues, setFormValues] = useState(initialValue);
const [formErrors, setFormErrors] = useState(initialValue);
const [touched, setTouched] = useState({password: false, confirm: false});
const [disabled, setDisabled] = useState(true);
const formSchema = yup.object().shape({
password: yup.string().required("Password required"),
confirm: yup
.string()
.oneOf([yup.ref("password"), null], "Passwords don't match")
});
const onChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
setTouched({...touched, [name]: true});
};
const onSubmit = (e) => {
e.preventDefault();
};
useEffect(() => {
yup
.reach(formSchema)
.validate(formValues, { abortEarly: false })
.then(() => {
setFormErrors({});
})
.catch((err) => {
const errors = {};
err.inner.forEach(error => {
if(touched[error.path]) errors[error.path] = error.message;
})
setFormErrors(errors);
});
formSchema.isValid(formValues).then(valid => setDisabled(!valid));
}, [formValues]);
return (
<div>
<form onSubmit={onSubmit}>
<label>
Password:
<input
type="text"
name="password"
onChange={onChange}
value={formValues.password}
/>
</label>
<label>
Confirm Password:
<input
type="text"
name="confirm"
onChange={onChange}
value={formValues.confirm}
/>
</label>
<button type="submit" disabled={disabled}>
Submit
</button>
<div className="errors">
<div>{touched.password && formErrors.password}</div>
<div>{touched.confirm && formErrors.confirm}</div>
</div>
</form>
</div>
);
}
Upvotes: 0