Working on a set_password.js
component that, you guessed it, lets the user set their password. It has them enter it twice to make sure they match. The password should have the criteria that it is at least 8 characters in length, has one uppercase, has one number, has one special character. Nothing ground breaking.
I know how to validate this stuff server side, but would rather validate it client side so the user doesn't have to wait for server response. I am struggling with how to do it.
I have a validate
function that takes the values from the fields and validates them.
function validate(values) {
const errors = {};
if (!values.password1) {
errors.password1 = 'This field cannot be empty.'
}
if (!values.password2) {
errors.password2 = 'This field cannot be empty.'
}
if (values.password1.length < 8) {
errors.password1 = 'The password provided is not long enough.'
}
if (values.password2.length < 8) {
errors.password2 = 'The password provided is not long enough.'
}
return errors
}
This is all I have so far, and I get an error Cannot read property 'length' of undefined
, so I am apparently putting this logic in the wrong area.
I'm starting to think that I should put it in the action so it is validated only after the user does onSubmit
. I guess it would look something like:
onSubmit(values) {
this.props.setPassword(values, this.props.match.params);
}
export function setPassword({ password1, password2 }, { id, key }) {
return function(dispatch) {
if (password1.length < 8 && password2.length < 8) {
axios
.post(
`${ROOT_URL}/api/auth/set_password/`,
{ password1, password2, id, key }
)
.then(response => {
console.log('Password changed')
})
.catch(error => {
dispatch(authError(error.response.data.non_field_errors[0]));
});
}
}
}
Anyway, so what is the correct way to accomplish this? Checking length of string, that it has at least one uppercase letter, that is has one special character, and one number?
EDIT:
Relevant form data:
// This renders errors regarding the form inputs
renderField(field) {
const {
label,
type,
name,
meta: {
touched,
error
}
} = field;
return (
<div className='form-group'>
<label>{label}</label>
<input
className='form-control'
type={type}
placeholder={label}
{...field.input}
/>
<div className='text-danger'>
{touched ? error : ""}
</div>
</div>
);
}
// The main body to be rendered
render() {
if (this.props.permitRender) {
const { handleSubmit } = this.props;
return (
<div>
<h3>Set New Password</h3>
<p>Type your new password twice. </p>
<p>It must be a minimum of 8 characters in length and contain at least:</p>
<ol>
<li>One uppercase character</li>
<li>One special character</li>
<li>One number</li>
</ol>
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
{this.renderAlert()}
<Field
label='Enter New Password'
name='password1'
type='password'
component={this.renderField}
/>
<Field
label='Confirm New Password'
name='password2'
type='password'
component={this.renderField}
/>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
);
} else if (!this.props.permitRender) {
return (
<div> { this.renderAlert() } </div>
);
}
}
Right now, your validating if
-statements are ordered somewhat wrongly. I don't think you can just assume any of the password values are set anyway.
It'd probably be better to first do a null-check on the string you want to validate, and only after that do the length- and character check.
The validation of what characters should be in there can probably be done by using one (or more, which is probably easier) regex patterns.
// null check
if (!values.password1) {
errors.password1 = 'This field cannot be empty.'
}
// After null checking, check length
else if (values.password1.length < 8) {
errors.password1 = 'The password provided is not long enough.'
}
// Check for capital letters
else if (/([A-Z]+)/g.test(values.password1) {
errors.password1 = 'You don\'t have any capital letters in there yo'
}
// Same here as before, pretty much
if (!values.password2) {
errors.password2 = 'This field cannot be empty.'
}
else if (values.password2.length < 8) {
errors.password2 = 'The password provided is not long enough.'
}
You can also do something like values.password1 && values.password1.length > 8
in your if statements to do each null check seperately.
https://regex101.com/ is a good place to try out and experiment with regex patterns if you do go that route.