AngularJS Form level validation
Allows to add form level validation to any form.
HTML
<div ng-app="myModule">
<h1>Form Validation Sample:Password and Repeat should be equals</h1>
<form
name="validatedForm"
mw-validate="{ notMatch: 'password1 == password2' }"
>
<!-- Show errors -->
<div ng-show="validatedForm.$invalid && ! validatedForm.$pristine" class="errors">
<div ng-repeat="(errorType, fields) in validatedForm.$error">
<p ng-repeat="field in fields">{{field.$name}} {{errorType}}</p>
</div>
</div>
<!-- Form Fields -->
<p><label>Username: </label><input type="text" name="name" ng-model="name"
required ng-minlength="5" ng-maxlength="20" size="20"/></p>
<p><label>Password: </label><input type="text" name="password" ng-model="password1"/></p>
<p><label>Repeat : </label><input type="text" name="password2" ng-model="password2"/></p>
<p><button ng-disabled="! validatedForm.$valid">Save</button></p>
<pre>{{ validatedForm | json }}</pre>
</form>
</div>
CSS
label {
display: inline-block;
width: 100px;
}
div.errors {
background-color: #FFBBBB;
margin: 10px;
padding: 4px;
}
form {
margin: 10px;
padding: 5px;
background-color: #EEEEFF;
}
form p {
margin-top: 5px;
}
JavaScript
angular.module('myModule', []);
/**
* Use: <form mw-validate="{ passwordMatch: 'password1 == password2' }" mw-name="form" >...</form>
* mg-validate: Object with form validations. object key y used as error key. Value is an expression evaluated
* for true or false. mw-name (or mw-name-exp) is used as control name.
*/
angular.module('myModule').directive('mwValidate', function($log) {
var noop = function() {};
var nullFormCtrl = {
isNull: true,
$addControl: noop,
$removeControl: noop,
$setValidity: noop,
$setDirty: noop
};
$log.info('Initializing mw-validate');
return {
restrict: 'A',
require: '^form', // Looks on parent also
// The linking function will add behavior to the template
// The fourth parameter is a NgModelController (http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController)
link: function(scope, element, attrs, parentFormCtrl) {
var modelCtrl = { $name: attrs.name || attrs.mwName },
nameExp = attrs.mwNameExp,
validateExpr = attrs.mwValidate;
var $error = this.$error = {}; // keep invalid keys here
parentFormCtrl = parentFormCtrl || nullFormCtrl ;
$log.info('Creating controller for: ' + modelCtrl.$name );
validateExpr = scope.$eval(validateExpr);
if ( ! validateExpr) {
return;
}
if (angular.isFunction(validateExpr)) {
validateExpr = { validator: validateExpr };
}
// TODO Is necessary?
parentFormCtrl.$addControl(modelCtrl);
element.bind('$destroy', function() {
parentFormCtrl.$removeControl(modelCtrl);
});
if ( nameExp ) {
scope.$watch( nameExp, function( newValue ) {
modelCtrl.$name = newValue;
...