angular-ui-validate
Advanced tools
Comparing version 1.0.0 to 1.2.1
{ | ||
"author": "AngularUI Team", | ||
"name": "angular-ui-validate", | ||
"version": "1.0.0", | ||
"homepage": "https://github.com/angular-ui/ui-validate", | ||
"authors": [ | ||
"AngularUI Team" | ||
], | ||
"description": "AngularUI ui-validate", | ||
"main": "src/validate.js", | ||
"keywords": [ | ||
"angular", | ||
"angularjs", | ||
"angularui", | ||
"angular-ui", | ||
"validation", | ||
"angular", | ||
"validation" | ||
], | ||
"main": "./dist/validate.js", | ||
"license": "MIT", | ||
"ignore": [ | ||
"**/.*", | ||
"node_modules", | ||
"bower_components", | ||
"test", | ||
"tests" | ||
], | ||
"dependencies": { | ||
"angular": "~1.4.0" | ||
"angular": ">= 1.3.0" | ||
}, | ||
"devDependencies": { | ||
"angular-mocks": ">=1.3.0", | ||
"jquery": ">=1.6" | ||
} | ||
} |
{ | ||
"name": "angular-ui-validate", | ||
"version": "1.0.0", | ||
"description": "AngularUI ui-validate", | ||
"main": "src/validate.js", | ||
"directories": { | ||
"test": "test" | ||
"version": "1.2.1", | ||
"author": "https://github.com/angular-ui/ui-validate/graphs/contributors", | ||
"license": "MIT", | ||
"homepage": "https://github.com/angular-ui/ui-validate", | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"del": "~1.2.0", | ||
"event-stream": "~3.3.1", | ||
"gulp": "~3.9.0", | ||
"gulp-bump": "^0.3.1", | ||
"gulp-concat": "~2.6.0", | ||
"gulp-footer": "~1.0.5", | ||
"gulp-git": "^1.4.0", | ||
"gulp-header": "~1.2.2", | ||
"gulp-jshint": "1.11.2", | ||
"gulp-plumber": "^1.0.1", | ||
"gulp-rename": "~1.2.2", | ||
"gulp-uglify": "~1.2.0", | ||
"jasmine-core": "^2.3.4", | ||
"jshint-stylish": "~2.0.1", | ||
"karma": "^0.13.9", | ||
"karma-chrome-launcher": "^0.2.0", | ||
"karma-coverage": "~0.5", | ||
"karma-firefox-launcher": "~0.1", | ||
"karma-jasmine": "~0.3", | ||
"karma-ng-html2js-preprocessor": "^0.1.0", | ||
"karma-phantomjs-launcher": "~0.2.1", | ||
"phantomjs": "^1.9.18", | ||
"run-sequence": "^1.1.2" | ||
}, | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"scripts": {}, | ||
"main": "./dist/validate.js", | ||
"repository": { | ||
@@ -18,15 +41,6 @@ "type": "git", | ||
"angular", | ||
"angularjs", | ||
"angularui", | ||
"angular-ui", | ||
"angular", | ||
"validation", | ||
"validation" | ||
], | ||
"author": "AngularUI Team", | ||
"license": "ISC", | ||
"bugs": { | ||
"url": "https://github.com/angular-ui/ui-validate/issues" | ||
}, | ||
"homepage": "https://github.com/angular-ui/ui-validate" | ||
"validate" | ||
] | ||
} |
@@ -1,5 +0,6 @@ | ||
# AngularUI ui-validate | ||
# ui-validate [![Build Status](https://travis-ci.org/angular-ui/ui-validate.svg?branch=master)](https://travis-ci.org/angular-ui/ui-validate) [![npm version](https://badge.fury.io/js/angular-ui-validate.svg)](http://badge.fury.io/js/angular-ui-validate) [![Bower version](https://badge.fury.io/bo/angular-ui-validate.svg)](http://badge.fury.io/bo/angular-ui-validate) [![Join the chat at https://gitter.im/angular-ui/ui-validate](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular-ui/ui-validate?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
General-purpose validator for ngModel. | ||
angular.js comes with several built-in validation mechanism for input fields (ngRequired, ngPattern etc.) but using | ||
Angular.js comes with several built-in validation mechanism for input fields (ngRequired, ngPattern etc.) but using | ||
an arbitrary validation function requires creation of a custom formatters and / or parsers. | ||
@@ -9,9 +10,54 @@ The ui-validate directive makes it easy to use any function(s) defined in scope as a validator function(s). | ||
@example `<input ui-validate=" 'myValidatorFunction($value)' ">` | ||
@example `<input ui-validate="{ foo : '$value > anotherModel', bar : 'validateFoo($value)' }">` | ||
@example `<input ui-validate="{ foo : '$value > anotherModel' }" ui-validate-watch=" 'anotherModel' ">` | ||
@example `<input ui-validate="{ foo : '$value > anotherModel', bar : 'validateFoo($value)' }" ui-validate-watch=" { foo : 'anotherModel' } ">` | ||
## Requirements | ||
@param ui-validate {string|object literal} If strings is passed it should be a scope's function to be used as a validator. | ||
If an object literal is passed a key denotes a validation error key while a value should be a validator function. | ||
In both cases validator function should take a value to validate as its argument and should return true/false indicating a validation result. | ||
- AngularJS | ||
## Usage | ||
You can get it from [Bower](http://bower.io/) | ||
```sh | ||
bower install angular-ui-validate | ||
``` | ||
Load the script files in your application: | ||
```html | ||
<script type="text/javascript" src="bower_components/angular/angular.js"></script> | ||
<script type="text/javascript" src="bower_components/angular-ui-validate/dist/validate.js"></script> | ||
``` | ||
Add the specific module to your dependencies: | ||
```javascript | ||
angular.module('myApp', ['ui.validate', ...]) | ||
``` | ||
## Development | ||
We use Karma and jshint to ensure the quality of the code. The easiest way to run these checks is to use grunt: | ||
```sh | ||
npm install -g gulp-cli | ||
npm install && bower install | ||
gulp | ||
``` | ||
The karma task will try to open Firefox and Chrome as browser in which to run the tests. Make sure this is available or change the configuration in `karma.conf.js` | ||
### Gulp watch | ||
`gulp watch` will automatically test your code and build a release whenever source files change. | ||
### How to release | ||
Use gulp to bump version, build and create a tag. Then push to GitHub: | ||
````sh | ||
gulp release [--patch|--minor|--major] | ||
git push --tags origin master # push everything to GitHub | ||
```` | ||
Travis will take care of testing and publishing to npm's registry (bower will pick up the change automatically). Finally [create a release on GitHub](https://github.com/angular-ui/ui-validate/releases/new) from the tag created by Travis. |
/** | ||
* General-purpose validator for ngModel. | ||
* angular.js comes with several built-in validation mechanism for input fields (ngRequired, ngPattern etc.) but using | ||
* an arbitrary validation function requires creation of a custom formatters and / or parsers. | ||
* an arbitrary validation function requires creation of custom directives for interact with angular's validation mechanism. | ||
* The ui-validate directive makes it easy to use any function(s) defined in scope as a validator function(s). | ||
* A validator function will trigger validation on both model and input changes. | ||
* | ||
* This utility bring 'ui-validate' directives to handle regular validations and 'ui-validate-async' for asynchronous validations. | ||
* | ||
* @example <input ui-validate=" 'myValidatorFunction($value)' "> | ||
@@ -12,2 +14,4 @@ * @example <input ui-validate="{ foo : '$value > anotherModel', bar : 'validateFoo($value)' }"> | ||
* @example <input ui-validate="{ foo : '$value > anotherModel', bar : 'validateFoo($value)' }" ui-validate-watch=" { foo : 'anotherModel' } "> | ||
* @example <input ui-validate-async=" 'myAsyncValidatorFunction($value)' "> | ||
* @example <input ui-validate-async="{ foo: 'myAsyncValidatorFunction($value, anotherModel)' }" ui-validate-watch=" 'anotherModel' "> | ||
* | ||
@@ -17,107 +21,179 @@ * @param ui-validate {string|object literal} If strings is passed it should be a scope's function to be used as a validator. | ||
* In both cases validator function should take a value to validate as its argument and should return true/false indicating a validation result. | ||
* It is possible for a validator function to return a promise, however promises are better handled by ui-validate-async. | ||
* | ||
* @param ui-validate-async {string|object literal} If strings is passed it should be a scope's function to be used as a validator. | ||
* If an object literal is passed a key denotes a validation error key while a value should be a validator function. | ||
* Async validator function should take a value to validate as its argument and should return a promise that resolves if valid and reject if not, | ||
* indicating a validation result. | ||
* ui-validate-async supports non asyncronous validators. They are wrapped into a promise. Although is recomented to use ui-validate instead, since | ||
* all validations declared in ui-validate-async are registered un ngModel.$asyncValidators that runs after ngModel.$validators if and only if | ||
* all validators in ngModel.$validators reports as valid. | ||
*/ | ||
angular.module('ui.validate',[]).directive('uiValidate', function () { | ||
angular.module('ui.validate',[]) | ||
.directive('uiValidate', ['$$uiValidateApplyWatch', '$$uiValidateApplyWatchCollection', function ($$uiValidateApplyWatch, $$uiValidateApplyWatchCollection) { | ||
return { | ||
restrict: 'A', | ||
require: 'ngModel', | ||
link: function (scope, elm, attrs, ctrl) { | ||
var validateFn, validators = {}, | ||
validateExpr = scope.$eval(attrs.uiValidate); | ||
link: function(scope, elm, attrs, ctrl) { | ||
var validateFn, validateExpr = scope.$eval(attrs.uiValidate); | ||
if (!validateExpr){ return;} | ||
if (!validateExpr) { | ||
return; | ||
} | ||
if (angular.isString(validateExpr)) { | ||
validateExpr = { validator: validateExpr }; | ||
validateExpr = { | ||
validator: validateExpr | ||
}; | ||
} | ||
angular.forEach(validateExpr, function (exprssn, key) { | ||
validateFn = function (valueToValidate) { | ||
var expression = scope.$eval(exprssn, { '$value' : valueToValidate }); | ||
angular.forEach(validateExpr, function(exprssn, key) { | ||
validateFn = function(modelValue, viewValue) { | ||
// $value is left for retrocompatibility | ||
var expression = scope.$eval(exprssn, { | ||
'$value': modelValue, | ||
'$modelValue': modelValue, | ||
'$viewValue': viewValue, | ||
'$name': ctrl.$name | ||
}); | ||
// Keep support for promises for retrocompatibility | ||
if (angular.isObject(expression) && angular.isFunction(expression.then)) { | ||
// expression is a promise | ||
if (angular.isUndefined(ctrl.$pending)) { | ||
ctrl.$pending = {}; | ||
} | ||
// set pending state until promise is resolved | ||
ctrl.$pending[key] = true; | ||
expression.then(function(){ | ||
expression.then(function() { | ||
ctrl.$setValidity(key, true); | ||
}, function(){ | ||
}, function() { | ||
ctrl.$setValidity(key, false); | ||
}); | ||
return valueToValidate; | ||
} else if (expression) { | ||
// expression is true | ||
ctrl.$setValidity(key, true); | ||
return valueToValidate; | ||
// Return as valid for now. Validity is updated when promise resolves. | ||
return true; | ||
} else { | ||
// expression is false | ||
ctrl.$setValidity(key, false); | ||
return valueToValidate; | ||
return expression; | ||
} | ||
}; | ||
validators[key] = validateFn; | ||
ctrl.$formatters.push(validateFn); | ||
ctrl.$parsers.push(validateFn); | ||
ctrl.$validators[key] = validateFn; | ||
}); | ||
function apply_watch(watch) | ||
{ | ||
//string - update all validators on expression change | ||
if (angular.isString(watch)) | ||
{ | ||
scope.$watch(watch, function(){ | ||
angular.forEach(validators, function(validatorFn){ | ||
validatorFn(ctrl.$modelValue); | ||
}); | ||
}); | ||
return; | ||
} | ||
// Support for ui-validate-watch | ||
if (attrs.uiValidateWatch) { | ||
$$uiValidateApplyWatch(scope, ctrl, scope.$eval(attrs.uiValidateWatch), attrs.uiValidateWatchObjectEquality); | ||
} | ||
if (attrs.uiValidateWatchCollection) { | ||
$$uiValidateApplyWatchCollection(scope, ctrl, scope.$eval(attrs.uiValidateWatchCollection)); | ||
} | ||
} | ||
}; | ||
}]) | ||
.directive('uiValidateAsync', ['$$uiValidateApplyWatch', '$$uiValidateApplyWatchCollection', '$timeout', '$q', function ($$uiValidateApplyWatch, $$uiValidateApplyWatchCollection, $timeout, $q) { | ||
//array - update all validators on change of any expression | ||
if (angular.isArray(watch)) | ||
{ | ||
angular.forEach(watch, function(expression){ | ||
scope.$watch(expression, function() | ||
{ | ||
angular.forEach(validators, function(validatorFn){ | ||
validatorFn(ctrl.$modelValue); | ||
}); | ||
}); | ||
}); | ||
return; | ||
} | ||
return { | ||
restrict: 'A', | ||
require: 'ngModel', | ||
link: function (scope, elm, attrs, ctrl) { | ||
var validateFn, validateExpr = scope.$eval(attrs.uiValidateAsync); | ||
//object - update appropriate validator | ||
if (angular.isObject(watch)) | ||
{ | ||
angular.forEach(watch, function(expression, validatorKey) | ||
{ | ||
//value is string - look after one expression | ||
if (angular.isString(expression)) | ||
{ | ||
scope.$watch(expression, function(){ | ||
validators[validatorKey](ctrl.$modelValue); | ||
}); | ||
} | ||
if (!validateExpr){ return;} | ||
//value is array - look after all expressions in array | ||
if (angular.isArray(expression)) | ||
{ | ||
angular.forEach(expression, function(intExpression) | ||
{ | ||
scope.$watch(intExpression, function(){ | ||
validators[validatorKey](ctrl.$modelValue); | ||
}); | ||
}); | ||
} | ||
}); | ||
if (angular.isString(validateExpr)) { | ||
validateExpr = { validatorAsync: validateExpr }; | ||
} | ||
angular.forEach(validateExpr, function (exprssn, key) { | ||
validateFn = function(modelValue, viewValue) { | ||
// $value is left for ease of use | ||
var expression = scope.$eval(exprssn, { | ||
'$value': modelValue, | ||
'$modelValue': modelValue, | ||
'$viewValue': viewValue, | ||
'$name': ctrl.$name | ||
}); | ||
// Check if it's a promise | ||
if (angular.isObject(expression) && angular.isFunction(expression.then)) { | ||
return expression; | ||
// Support for validate non-async validators | ||
} else { | ||
return $q(function(resolve, reject) { | ||
setTimeout(function() { | ||
if (expression) { | ||
resolve(); | ||
} else { | ||
reject(); | ||
} | ||
}, 0); | ||
}); | ||
} | ||
} | ||
}; | ||
ctrl.$asyncValidators[key] = validateFn; | ||
}); | ||
// Support for ui-validate-watch | ||
if (attrs.uiValidateWatch){ | ||
apply_watch( scope.$eval(attrs.uiValidateWatch) ); | ||
$$uiValidateApplyWatch( scope, ctrl, scope.$eval(attrs.uiValidateWatch), attrs.uiValidateWatchObjectEquality); | ||
} | ||
if (attrs.uiValidateWatchCollection) { | ||
$$uiValidateApplyWatchCollection(scope, ctrl, scope.$eval(attrs.uiValidateWatchCollection)); | ||
} | ||
} | ||
}; | ||
}); | ||
}]) | ||
.service('$$uiValidateApplyWatch', function () { | ||
return function (scope, ctrl, watch, objectEquality) { | ||
var watchCallback = function () { | ||
ctrl.$validate(); | ||
}; | ||
//string - update all validators on expression change | ||
if (angular.isString(watch)) { | ||
scope.$watch(watch, watchCallback, objectEquality); | ||
//array - update all validators on change of any expression | ||
} else if (angular.isArray(watch)) { | ||
angular.forEach(watch, function (expression) { | ||
scope.$watch(expression, watchCallback, objectEquality); | ||
}); | ||
//object - update appropriate validator | ||
} else if (angular.isObject(watch)) { | ||
angular.forEach(watch, function (expression/*, validatorKey*/) { | ||
//value is string - look after one expression | ||
if (angular.isString(expression)) { | ||
scope.$watch(expression, watchCallback, objectEquality); | ||
} | ||
//value is array - look after all expressions in array | ||
if (angular.isArray(expression)) { | ||
angular.forEach(expression, function (intExpression) { | ||
scope.$watch(intExpression, watchCallback, objectEquality); | ||
}); | ||
} | ||
}); | ||
} | ||
}; | ||
}) | ||
.service('$$uiValidateApplyWatchCollection', function () { | ||
return function (scope, ctrl, watch) { | ||
var watchCallback = function () { | ||
ctrl.$validate(); | ||
}; | ||
//string - update all validators on expression change | ||
if (angular.isString(watch)) { | ||
scope.$watchCollection(watch, watchCallback); | ||
//array - update all validators on change of any expression | ||
} else if (angular.isArray(watch)) { | ||
angular.forEach(watch, function (expression) { | ||
scope.$watchCollection(expression, watchCallback); | ||
}); | ||
//object - update appropriate validator | ||
} else if (angular.isObject(watch)) { | ||
angular.forEach(watch, function (expression/*, validatorKey*/) { | ||
//value is string - look after one expression | ||
if (angular.isString(expression)) { | ||
scope.$watchCollection(expression, watchCallback); | ||
} | ||
//value is array - look after all expressions in array | ||
if (angular.isArray(expression)) { | ||
angular.forEach(expression, function (intExpression) { | ||
scope.$watchCollection(intExpression, watchCallback); | ||
}); | ||
} | ||
}); | ||
} | ||
}; | ||
}); |
@@ -40,3 +40,3 @@ describe('uiValidate', function () { | ||
expect(scope.form.input.$valid).toBeTruthy(); | ||
expect(scope.form.input.$error).toEqual({validator: false}); | ||
expect(scope.form.input.$error).toEqual({}); | ||
})); | ||
@@ -117,5 +117,25 @@ | ||
expect(scope.form.input.$valid).toBe(true); | ||
expect(scope.form.input.$error.validator).toBe(false); | ||
expect(scope.form.input.$error.validator).toBeUndefined(); | ||
}); | ||
it('should watch the object deeply and refire the single validator', function () { | ||
scope.watchMe = { test: false }; | ||
compileAndDigest('<input name="input" ng-model="value" ui-validate="\'watchMe.test==true\'" ui-validate-watch="\'watchMe\'" ui-validate-watch-object-equality="true">', scope); | ||
expect(scope.form.input.$valid).toBe(false); | ||
expect(scope.form.input.$error.validator).toBe(true); | ||
scope.$apply('watchMe.test=true'); | ||
expect(scope.form.input.$valid).toBe(true); | ||
expect(scope.form.input.$error.validator).toBeUndefined(); | ||
}); | ||
it('should watch the array and refire the single validator', function () { | ||
scope.watchMe = []; | ||
compileAndDigest('<input name="input" ng-model="value" ui-validate="\'watchMe.length > 0\'" ui-validate-watch-collection="\'watchMe\'">', scope); | ||
expect(scope.form.input.$valid).toBe(false); | ||
expect(scope.form.input.$error.validator).toBe(true); | ||
scope.$apply('watchMe.push(1)'); | ||
expect(scope.form.input.$valid).toBe(true); | ||
expect(scope.form.input.$error.validator).toBeUndefined(); | ||
}); | ||
it('should watch the string and refire all validators', function () { | ||
@@ -129,4 +149,4 @@ scope.watchMe = false; | ||
expect(scope.form.input.$valid).toBe(true); | ||
expect(scope.form.input.$error.foo).toBe(false); | ||
expect(scope.form.input.$error.bar).toBe(false); | ||
expect(scope.form.input.$error.foo).toBeUndefined(); | ||
expect(scope.form.input.$error.bar).toBeUndefined(); | ||
}); | ||
@@ -143,3 +163,3 @@ | ||
expect(scope.form.input.$valid).toBe(false); | ||
expect(scope.form.input.$error.foo).toBe(false); | ||
expect(scope.form.input.$error.foo).toBeUndefined(); | ||
expect(scope.form.input.$error.bar).toBe(true); | ||
@@ -150,7 +170,7 @@ scope.$apply('watchBar=true'); | ||
expect(scope.form.input.$error.foo).toBe(true); | ||
expect(scope.form.input.$error.bar).toBe(false); | ||
expect(scope.form.input.$error.bar).toBeUndefined(); | ||
scope.$apply('watchFoo=true'); | ||
expect(scope.form.input.$valid).toBe(true); | ||
expect(scope.form.input.$error.foo).toBe(false); | ||
expect(scope.form.input.$error.bar).toBe(false); | ||
expect(scope.form.input.$error.foo).toBeUndefined(); | ||
expect(scope.form.input.$error.bar).toBeUndefined(); | ||
}); | ||
@@ -164,3 +184,3 @@ | ||
compileAndDigest('<input name="input" ui-validate="\'validate($value)\'">', scope); | ||
}).toThrow(new Error('No controller: ngModel')); | ||
}).toThrow(); | ||
})); | ||
@@ -171,2 +191,20 @@ it('should have no effect if validate expression is empty', inject(function () { | ||
}); | ||
describe('additional scope variables', function () { | ||
it('should pass name of the field to the scope', function () { | ||
scope.validate = function () { return true; }; | ||
spyOn(scope, 'validate').and.callThrough(); | ||
compileAndDigest('<input name="firstname" ng-model="value" ui-validate="\'validate($name)\'">', scope); | ||
expect(scope.validate).toHaveBeenCalledWith('firstname'); | ||
scope.validate.calls.reset(); | ||
compileAndDigest('<input name="lastname" ng-model="value" ui-validate-async="\'validate($name)\'">', scope); | ||
expect(scope.validate).toHaveBeenCalledWith('lastname'); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
46814
14
0
698
0
63
23
2
1
2