Skip to content

Commit 95767fa

Browse files
authored
Merge pull request #31 from sagrawal14/validation-classes
Ability to distinguish between different type of errors
2 parents b41bcad + 942151d commit 95767fa

7 files changed

+135
-30
lines changed

bootstrap-angular-validation.iml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<content url="file://$MODULE_DIR$">
66
<excludeFolder url="file://$MODULE_DIR$/.idea" />
77
<excludeFolder url="file://$MODULE_DIR$/bower_components" />
8+
<excludeFolder url="file://$MODULE_DIR$/dist" />
89
<excludeFolder url="file://$MODULE_DIR$/node_modules" />
910
</content>
1011
<orderEntry type="inheritedJdk" />

bower.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
{
22
"name": "bootstrap-angular-validation",
33
"description": "Bootstrap form validation in Angular like jQuery but w/o jQuery.",
4-
"main": "dist/bootstrap-angular-validation.min.js",
4+
"main": [
5+
"dist/bootstrap-angular-validation-all.min.js"
6+
],
57
"dependencies": { },
68
"devDependencies": {
79
"angular": "^1.5.5"
@@ -15,6 +17,7 @@
1517
"**/.*",
1618
"node_modules",
1719
"bower_components",
20+
"test-app",
1821
"src"
1922
],
2023
"repository": {

dist/bootstrap-angular-validation-all.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/bootstrap-angular-validation-core.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/directives/validation.directive.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ angular.module('bootstrap.angular.validation').directive('bsValidation', [
4040
var validationMessageService = validationService.getValidationMessageService(displayErrorAs);
4141

4242
// Register generic custom validators if added to element
43-
angular.forEach(validationService.getValidators(), function(key) {
43+
angular.forEach(validationService.getValidators(), function(validator) {
44+
var key = validator.name;
4445
var attrValue = $element.attr(key);
4546
if ($attr[key] || (angular.isDefined(attrValue) && attrValue !== false)) {
46-
validationService.addValidator($scope, $attr, ngModelController, key);
47+
validationService.addValidator($scope, $element, $attr, ngModelController, validator);
4748
}
4849
});
4950

@@ -78,6 +79,8 @@ angular.module('bootstrap.angular.validation').directive('bsValidation', [
7879
}
7980

8081
function displayOrHideValidationState() {
82+
validationService.toggleErrorKeyClasses($formGroupElement, ngModelController.$error);
83+
8184
if (!displayValidationState) {
8285
hideSuccess();
8386
return hideError();

src/services/validation.service.js

Lines changed: 72 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,42 @@ angular.module('bootstrap.angular.validation').factory('BsValidationService', ['
1212
var customFormGroup = '[bs-form-group]';
1313
var formGroupClass = '.form-group';
1414

15-
var genericValidators = {
16-
digits: function(value) {
15+
var _genericValidators = [{
16+
name: 'digits',
17+
validateFn: function(value) {
1718
return (/^\d+$/).test(value);
18-
},
19-
equalto: function(value, $scope, attr) {
19+
}
20+
}, {
21+
name: 'equalto',
22+
validateFn: function(value, $scope, attr) {
2023
return value + '' === $scope.$eval(attr.equalto) + '';
21-
},
22-
number: function(value) {
24+
}
25+
}, {
26+
name: 'number',
27+
validateFn: function(value) {
2328
return (/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/).test(value);
24-
},
25-
min: function(value, $scope, attr) {
29+
}
30+
}, {
31+
name: 'min',
32+
validateFn: function(value, $scope, attr) {
2633
return parseFloat(value) >= parseFloat(attr.min);
27-
},
28-
max: function(value, $scope, attr) {
34+
}
35+
}, {
36+
name: 'max',
37+
validateFn: function(value, $scope, attr) {
2938
return parseFloat(value) <= parseFloat(attr.max);
30-
},
31-
length: function(value, $scope, attr) {
39+
}
40+
}, {
41+
name: 'length',
42+
validateFn: function(value, $scope, attr) {
3243
return value.length === parseInt(attr.length);
33-
},
34-
strictemail: function(value) {
44+
}
45+
}, {
46+
name: 'strictemail',
47+
validateFn: function(value) {
3548
return new RegExp(/^[_a-z0-9]+(\.[_a-z0-9]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/).test(value);
3649
}
37-
};
50+
}];
3851

3952
function getTrigger($element, triggerEvent) {
4053
var attributeName = 'bs-trigger';
@@ -51,17 +64,17 @@ angular.module('bootstrap.angular.validation').factory('BsValidationService', ['
5164
return validationConfig.shouldValidateOn(triggerEvent);
5265
}
5366

67+
function removeClassByPrefix(element, prefix) {
68+
var regx = new RegExp('\\b' + prefix + '.*\\b', 'g');
69+
element[0].className = element[0].className.replace(regx, '').replace(/\s\s+/g, ' ');
70+
return element;
71+
}
72+
5473
var meta = ['matchName'];
5574

5675
return {
57-
/**
58-
* Search all the input element inside the given DOM element and apply the 'bs-validation' directive so we
59-
* need not a add it for every form element.
60-
*/
6176
getValidators: function() {
62-
var builtIn = ['equalto', 'min', 'max', 'number', 'digits', 'length'];
63-
var additional = Object.keys(genericValidators);
64-
return builtIn.concat(additional);
77+
return _genericValidators;
6578
},
6679

6780
getMetaInformation: function($element) {
@@ -87,13 +100,32 @@ angular.module('bootstrap.angular.validation').factory('BsValidationService', ['
87100
}
88101
},
89102

90-
addValidator: function($scope, $attr, ngModelController, validatorKey) {
91-
ngModelController.$validators[validatorKey] = function(modelValue, viewValue) {
103+
addValidator: function($scope, $element, $attr, ngModelController, validator) {
104+
ngModelController.$validators[validator.name] = function(modelValue, viewValue) {
92105
var value = modelValue || viewValue;
93-
return ngModelController.$isEmpty(value) || genericValidators[validatorKey](value, $scope, $attr);
106+
if (ngModelController.$isEmpty(value)) {
107+
return true;
108+
}
109+
110+
// See https://github.com/sagrawal14/angular-extras/blob/v0.1.3/src/extras/array.js#L91 for "find" function
111+
return validator.validateFn(value, $scope, $attr);
94112
};
95113
},
96114

115+
/**
116+
* Add a custom validator to the list of generic validators.
117+
* @param genericValidationObject for example, to a add a generic validator to accept either "foo" or "bar":
118+
* {
119+
* name: 'foobar',
120+
* validateFn: function(value, $scope, attr) {
121+
* return value === 'foo' || value === 'bar';
122+
* }
123+
* }
124+
*/
125+
addGenericValidator: function(genericValidationObject) {
126+
_genericValidators.push(genericValidationObject);
127+
},
128+
97129
displayErrorPreference: function($element, $attr) {
98130
var attrName = displayErrorAsAttrName;
99131
if ($attr[attrName]) {
@@ -204,6 +236,21 @@ angular.module('bootstrap.angular.validation').factory('BsValidationService', ['
204236

205237
shouldValidateOnSubmit: function($element) {
206238
return getTrigger($element, 'submit');
239+
},
240+
241+
/**
242+
* Add or remove various classes on form-group element. For example, if an input has two errors "required" & "min"
243+
* then whenever the validation fails, form-group element will have classes like "bs-has-error-required" or
244+
* "bs-has-error-min".
245+
* @param $formGroupElement jQLite/jQuery form-group element
246+
* @param errors Errors object as returned by ngModelController.$error
247+
*/
248+
toggleErrorKeyClasses: function ($formGroupElement, errors) {
249+
removeClassByPrefix($formGroupElement, 'bs-has-error-');
250+
251+
angular.forEach(errors, function (value, key) {
252+
$formGroupElement.addClass('bs-has-error-' + key);
253+
});
207254
}
208255

209256
};

test-app/basic.html

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Basic Bootstrap + Angular Validation</title>
6+
<link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.css" />
7+
</head>
8+
<body>
9+
<div ng-app="bavApp" class="container" ng-controller="FooController">
10+
<form class="form-horizontal" ng-submit="saveMe()">
11+
12+
<div class="form-group">
13+
<label for="inputEmail3" class="col-sm-2 control-label">Email</label>
14+
15+
<div class="col-sm-10">
16+
<input type="email" class="form-control" id="inputEmail3" placeholder="Email" ng-model="email"
17+
required name="password">
18+
</div>
19+
</div>
20+
21+
<div class="form-group">
22+
<label for="inputPassword3" class="col-sm-2 control-label">Password</label>
23+
24+
<div class="col-sm-10">
25+
<input type="url" class="form-control" id="inputPassword3" placeholder="Password"
26+
ng-model="password" required="required" min="2" max="5" name="password">
27+
</div>
28+
</div>
29+
30+
<div class="form-group">
31+
<div class="col-sm-offset-2 col-sm-10">
32+
<button type="submit" class="btn btn-default">Sign in</button>
33+
</div>
34+
</div>
35+
</form>
36+
37+
</div>
38+
39+
<script src="../bower_components/angular/angular.min.js"></script>
40+
<script src="../dist/bootstrap-angular-validation-all.min.js"></script>
41+
<script>
42+
var app = angular.module("bavApp", ["bootstrap.angular.validation"]);
43+
44+
app.controller("FooController", function ($scope) {
45+
$scope.saveMe = function () {
46+
alert("Thanks");
47+
};
48+
});
49+
</script>
50+
</body>
51+
</html>

0 commit comments

Comments
 (0)