A controller-side validator for AngularJS.
AngularJS provides powerful form validation features through a set of dedicated directives. This validation mechanisms are well described here and here.
Built-in directives apply validation constraints on each user interaction, and add errors state details to scopes. This approach is extremely powerful to implement highly interactive forms, with a large variety of UX patterns. But it also has drawbacks :
- It puts a lot of code in views, that mixes different concerns at the same place: presentation, business validation rules, error messages, user interactions ...
- It introduces a complexity overhead on forms that do not require rich error handling,
- Custom validation constraints requires to write new directives: these custom directives generally contain a lot of technical/structural code for only few lines of business code.
angular-dataValidator provides an alternative way to validate forms, based on controller-side validation rules. It is definitely less powerful than built-in AngularJS directives, but for forms with simple interactivity, it allows to write simpler code with a cleaner separation of concerns.
angular-dataValidator is under development and still requires a lot of work :
- A comprehensive documentation,
Validator.register(constraintName, constraintFunction)
to register custom constraints,- Global error handling configuration,
- Error messages localization support,
- Options on validate & check functions :
flatten
,stopOnError
, - Packaging as a bower component.
In an AngularJS view, we declare a login form with login, password input fields and a submit button:
<form>
<h1>Please login</h1>
<input placeholder="Login (email address)" ng-model="login" type="text"/>
<input placeholder="Password" ng-model="password" type="password"/>
<button ng-click="submit()">Submit</button>
</form>
In the controller, we declare the form validation constraints :
var validationRules = Validator({
'login': [
Validator('Login is required').required(),
Validator('Login must be a valid email address').email()
],
'password': Validator('Password is required').required()
});
Then, we add a submit function on the scope that is called when user clicks on the submit button :
$scope.submit = function () {
delete $scope.errors;
delete $scope.message;
var errors = validationRules.check($scope);
if (errors !== undefined) {
$scope.errors = errors;
} else {
$scope.message = 'Login Success !';
}
};
It validates user inputs, and adds an error object or a confirmation message to the scope, depending on the validation result.
Finally, we display confirmation and error messages in the view :
<div ng-show="message">{{message}}</div>
<form>
<h1>Please login</h1>
<input placeholder="Login (email address)" ng-model="login" type="text"/>
<div ng-show="errors.login">{{errors.login.message}}</div>
<input placeholder="Password" ng-model="password" type="password"/>
<div ng-show="errors.password">{{errors.password.message}}</div>
<button ng-click="submit()">Submit</button>
</form>
Get the latest zip distribution file from /downloads directory, install it and add <script src="path/to/validator-min.js"></script>
in your AngularJS application. Then, define a dependency to the dataValidator module in your AngularJS application:
angular.module('myApp', ['dataValidator' /*, 'ngRoute', ... */]);
dataValidator module provides the Validator service, just get it by using AngularJS dependency injection :
angular.module('myApp').controller('myCtrl', function ($scope, Validator) {
/* ... */
};
First we create a rule object :
var rule = validator('The field is required, and its min length is 10.').required().minLength(10);
A rule object is composed of an error message passed to the Validator service, and a list of constraints that are defined by chaining function calls.
Once the rule object is created, it provides two functions to apply validation constraints:
The check
function takes a value as input and applies validation constraints on it. It returns undefined
if all the constraints pass, or an error object if a constraint does not pass :
var error = rule.check('foobar');
if (error === undefined) {
console.log('Success !');
} else {
console.log('Error: ' + error.message);
}
The validate
function validates input value and uses the promise AngularJS API to handle success and error cases :
rule.validate('foobar').then(function () {
console.log('Success !');
}, function (error) {
console.log('Error: ' + error.message);
});
Validator service can also construct rules that validate JavaScript objects. The rules are constructed by passing an object to the Validator service:
// Construct the validation rules
var rules = Validator({
'login': [
Validator('Login is required').required(),
Validator('Login must be a valid email address').email()
],
'password': Validator('Password is required').required()
});
// Object to validate
var credentials = {
login: '[email protected]',
password: 'foobar-password'
};
// Apply rules on input object
rules.validate(credentials).then(function () {
console.log('Success !');
}, function (errors) {
angular.forEach(errors, function(error){
console.log('Error: ' + error.message);
});
});
The constraint descriptor passed to Validator(...)
is a flat key-value object. The keys are $parse
expressions, and values are sets of constraint declarations applied on the result of the $parse
evaluation.
Here is an example with a nested input object :
var signup = {
userDetail: {
firstName: 'John',
lastName: 'Doe',
email: '[email protected]'
}
account: {
username: 'johndoe'
password: 'Foob@r123'
}
}
var validationRules = Validator({
'userDetail.firstName': Validator('First name is required').required(),
'userDetail.lastName': Validator('Last name is required').required(),
'userDetail.email': [
Validator('Email address is required').required(),
Validator('Please enter a valid email address').email()
],
'account.username': [
Validator('Username is required').required(),
Validator('Username must only contain alphanumerical characters').alphanum()
],
'account.password': [
Validator('Password is required').required(),
Validator('A minimum password length of 8 characters is required').minLength(8),
Validator('Password must contain at least a lowercase character, an uppercase character and a numerical character').match(/[a-z]+/).match(/[A-Z]+/).match(/[0-9]+/)
]
});
validationRules.validate($scope).then(function ok() {
$scope.message = 'Success !';
}, function ko(errors) {
$scope.errors = errors;
});
TODO
TODO
TODO
TODO
- Install NodeJs, Grunt and Bower,
- Clone the github repository, and run the following command lines to donwload NodeJS and Bower dependencies:
npm install
bower install
Grunt tasks are :
grunt test
: Apply jshint checks and karma unit tests,grunt clean
: removes all the build file,grunt build
: build a dist version in /downloads directory,grunt sampleapp
: Launch a sample application on port 9000.