Writing new validator
A validator has to follow the syntax:
const customValidator = function() {
return {
validate: function(input) {
return {
valid: ...,
message: ...,
meta: {
key: value,
...
},
};
},
};
};
The following example illustrates how to develop a simple validator which validates a password. The validator will treat a password as valid, if it satisfies all the conditions below:
- Must be more than 8 characters long
- Must contain at least one upper case character
- Must contain at least one lower case character
- Must contain at least one digit
In fact, you can add more conditions to make a secure password.
const strongPassword = function () {
return {
validate: function (input) {
const value = input.value;
if (value === '') {
return {
valid: true,
};
}
if (value.length < 8) {
return {
valid: false,
};
}
if (value === value.toLowerCase()) {
return {
valid: false,
};
}
if (value === value.toUpperCase()) {
return {
valid: false,
};
}
if (value.search(/[0-9]/) < 0) {
return {
valid: false,
};
}
return {
valid: true,
};
},
};
};
Registering custom validator
There are two ways to reuse a custom validator.
Adding to FormValidation.validators
namespace
const strongPassword = function() {
...
};
FormValidation.validators.checkPassword = strongPassword;
FormValidation.formValidation(
document.getElementById('demoForm'),
{
fields: {
pwd: {
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
},
checkPassword: {
message: 'The password is too weak'
},
}
}
},
}
);
We register a new validator named
checkPassword
which is implemented by the
strongPassword
function. Since the validators are distinct by the names, the new validator name (
checkPassword
, in the example above) has to be different with
built-in validators.
Registering custom validator
This approach should be used when the FormValidation
namespace doesn't exist. For example, when the library is used with ES6 module.
const strongPassword = function() {
...
};
FormValidation
.formValidation(
document.getElementById('demoForm'),
{
fields: {
pwd: {
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
},
checkPassword: {
message: 'The password is too weak'
},
}
}
},
}
)
.registerValidator('checkPassword', strongPassword);
Adding custom message
Basically, the custom validator above works fine. It returns false
if the password doesn't satisfy any of conditions we define. The limitation here is that the user don't know which condition the password doesn't pass. It informs the same The password is too weak
message all the times.
To improve that, we can set a dynamic error message in custom validator:
const customValidator = function() {
return {
validate: function(input) {
if (...) {
return {
valid: true,
message: 'The error message',
};
}
return {
valid: false,
message: 'Other error message',
};
},
};
};
Our password checker now indicates the reason for a weak password:
const strongPassword = function () {
return {
validate: function (input) {
const value = input.value;
if (value === '') {
return {
valid: true,
};
}
if (value.length < 8) {
return {
valid: false,
message: 'The password must be more than 8 characters long',
};
}
if (value === value.toLowerCase()) {
return {
valid: false,
message: 'The password must contain at least one upper case character',
};
}
if (value === value.toUpperCase()) {
return {
valid: false,
message: 'The password must contain at least one lower case character',
};
}
if (value.search(/[0-9]/) < 0) {
return {
valid: false,
message: 'The password must contain at least one digit',
};
}
return {
valid: true,
};
},
};
};
Now, the form shows exactly condition that we want the password to satisfy.
Adding meta data
The rules used in example above are too simple and can't cover most popular cases of weak password. For example, it doesn't check the simple password such as 123456, abcdef, .etc.
In this section, we will use the awesome Dropbox's
zxcvbn library to build a password strength meter.
For anyone who haven't known about zxcvbn library, it's a password strength estimator inspired by password crackers developed by Dropbox. It can recognize and weighs 30k common passwords. For more information about this library, you can refer to
its official page.
It's quite easy to
use it to see how strong a given password is:
const result = zxcvbn(password);
result.score;
result.feedback.warning;
score
is an integer number between 0 and 4 that indicates the strength level:
Score | Description |
---|
0 | Too guessable: risky password |
1 | Very guessable: protection from throttled online attacks |
2 | Somewhat guessable: protection from unthrottled online attacks |
3 | Safely unguessable: moderate protection from offline slow-hash scenario |
4 | Very unguessable: strong protection from offline slow-hash scenario |
Our custom validator will use zxcvbn and include score in its validation result:
const strongPassword = function () {
return {
validate: function (input) {
const value = input.value;
if (value === '') {
return {
valid: true,
};
}
const result = zxcvbn(value);
const score = result.score;
const message = result.feedback.warning || 'The password is weak';
const minimalScore = input.options && input.options.minimalScore ? input.options.minimalScore : 3;
if (score < minimalScore) {
return {
valid: false,
message: message,
meta: {
score: score,
},
};
}
},
};
};
Next, we will use the score which is inclued the meta data of validation result to show up a password strength meter.
Bootstrap's progress is used to simply demo the functionality.
<input type="password" class="form-control" name="pwd" autocomplete="off" />
<div class="progress mt-2" id="progressBar" style="opacity: 0;">
<div class="progress-bar progress-bar-striped progress-bar-animate" style="width: 100%"></div>
</div>
FormValidation
.formValidation(
document.getElementById('demoForm'),
{
fields: {
...
},
plugins: {
...
},
}
)
.registerValidator('checkPassword', strongPassword)
.on('core.validator.validated', function(e) {
if (e.field === 'pwd' && e.validator === 'checkPassword') {
const progressBar = document.getElementById('progressBar');
if (e.result.meta) {
const score = e.result.meta.score;
const width = (score === 0) ? '1%' : score * 25 + '%';
progressBar.style.opacity = 1;
progressBar.style.width = width;
} else {
progressBar.style.opacity = 0;
progressBar.style.width = '0%';
}
}
});
Lastly, for a full working demonstration, you can play with the following form:
Try to enter simple passwords such as 123456, abcdef, abc123 to see how they are treated
See also