angular-async-validator
Advanced tools
Comparing version 0.2.0 to 0.2.1
declare module AsyncValidator { | ||
interface IValidationFn { | ||
(value: string | angular.INgModelController, options?: IOptions): boolean | angular.IPromise<boolean>; | ||
(value: string | angular.INgModelController, options?: any): boolean | angular.IPromise<any>; | ||
} | ||
@@ -20,6 +20,7 @@ type IValidateFactory = Function | Array<string | Function>; | ||
silentRejection?: boolean; | ||
returnValue?: boolean; | ||
} | ||
module Services { | ||
class AsyncValidator { | ||
run: <T>(name: string, value: T, options?: IOptions) => angular.IPromise<T>; | ||
run: <T>(name: string, value: T, options?: any, returnValue?: boolean) => angular.IPromise<T>; | ||
options: (name: string) => IOptions; | ||
@@ -26,0 +27,0 @@ validator: (name: string) => IValidationFn; |
@@ -12,28 +12,23 @@ var AsyncValidator; | ||
}); | ||
this.run = function (name, value, options) { | ||
this.run = function (name, value, options, returnValue) { | ||
if (typeof provider.validations[name] === 'undefined' || typeof provider.validations[name].validator !== 'function') { | ||
return $q.reject(name + ' isn\'t a registered async validator'); | ||
return $q.reject("" + name + " isn't a registered async validator"); | ||
} | ||
options = angular.extend({}, provider.validations[name].options.options, options); | ||
return new $q(function (resolve, reject) { | ||
try { | ||
resolve(provider.validations[name].validator(value, options)); | ||
} | ||
catch (e) { | ||
reject(e); | ||
} | ||
}).then(function (result) { | ||
return new $q(function asyncValidatorRunResolver(resolve) { | ||
resolve(provider.validations[name].validator(value, options)); | ||
}).then(function asyncValidatorResolved(result) { | ||
if (!!result) { | ||
return value; | ||
return returnValue === false ? true : value; | ||
} | ||
return $q.reject(); | ||
}, function (err) { | ||
}, function asyncValidatorRejected(e) { | ||
if (provider.validations[name].options.silentRejection) { | ||
return $q.reject(err); | ||
return $q.reject(e); | ||
} | ||
if (angular.isString(err)) { | ||
throw new Error(err); | ||
if (angular.isString(e)) { | ||
throw new Error(e); | ||
} | ||
else { | ||
throw err; | ||
throw e; | ||
} | ||
@@ -75,3 +70,4 @@ }); | ||
removeSync: true, | ||
silentRejection: true | ||
silentRejection: true, | ||
returnValue: true | ||
}; | ||
@@ -112,3 +108,3 @@ this.$get = Services.AsyncValidator.instance(this); | ||
angular.forEach(this.$pending, function (pending) { | ||
_this.add(pending.model, pending.scope, pending.options); | ||
_this.add(pending.model, pending.scope, pending.attrs); | ||
}); | ||
@@ -118,3 +114,3 @@ this.$pending.length = 0; | ||
}; | ||
AsyncForm.prototype.add = function (model, scope, options) { | ||
AsyncForm.prototype.add = function (model, scope, attrs) { | ||
if (!this.callback) { | ||
@@ -124,7 +120,7 @@ this.$pending.push({ | ||
scope: scope, | ||
options: options | ||
attrs: attrs | ||
}); | ||
return; | ||
} | ||
this.callback(model, scope, options); | ||
this.callback(model, scope, attrs); | ||
}; | ||
@@ -142,6 +138,9 @@ AsyncForm.$inject = []; | ||
angular.forEach(attrs.$attr, function (value, key) { | ||
if (!attrs[key]) { | ||
return; | ||
} | ||
var matches; | ||
if ((matches = value.match(optionsRegex))) { | ||
if (matches[1]) { | ||
if (typeof (evaled = scope.$eval(attrs[key])) === 'object') { | ||
if (angular.isObject(evaled = scope.$eval(attrs[key]))) { | ||
if (typeof opts[matches[1]] !== 'object') { | ||
@@ -154,3 +153,3 @@ opts[matches[1]] = {}; | ||
else { | ||
if (typeof (evaled = scope.$eval(attrs[key])) === 'object') { | ||
if (angular.isObject(evaled = scope.$eval(attrs[key]))) { | ||
angular.extend(opts['__'], evaled); | ||
@@ -163,3 +162,3 @@ } | ||
} | ||
function addValidators(validateExpr, AsyncValidator, ctrl, scope, $q, _options) { | ||
function addValidators(validateExpr, AsyncValidator, ctrl, scope, $q, $attrs) { | ||
if (angular.isString(validateExpr)) { | ||
@@ -178,3 +177,3 @@ if (AsyncValidator.validator(validateExpr)) { | ||
angular.forEach(validateExpr, function (exprssn, key) { | ||
var opts = AsyncValidator.options(key), modelOptions = _options['__'], validator = key; | ||
var opts = AsyncValidator.options(key), validator = key; | ||
if (angular.isString(exprssn) && angular.equals(opts, {})) { | ||
@@ -195,10 +194,10 @@ opts = AsyncValidator.options(exprssn); | ||
} | ||
else if (typeof _options[key] === 'object') { | ||
angular.extend(modelOptions, _options[key]); | ||
} | ||
if (typeof _options[validator] === 'object') { | ||
angular.extend(modelOptions, _options[validator]); | ||
} | ||
ctrl.$asyncValidators[key] = function validationFn(val) { | ||
var value; | ||
var value, _options = parseOptions(scope, $attrs), modelOptions = _options['__']; | ||
if (typeof _options[key] === 'object') { | ||
angular.extend(modelOptions, _options[key]); | ||
} | ||
if (typeof _options[validator] === 'object') { | ||
angular.extend(modelOptions, _options[validator]); | ||
} | ||
if (opts && opts.valueFrom === false) { | ||
@@ -220,3 +219,3 @@ value = ctrl; | ||
if (exprssn === '__VALIDATOR__' || exprssn === validator) { | ||
return AsyncValidator.run(validator, value, modelOptions); | ||
return AsyncValidator.run(validator, value, modelOptions, false); | ||
} | ||
@@ -254,14 +253,14 @@ else { | ||
this.link = function (scope, el, attrs, ctrls) { | ||
var validateExpr = scope.$eval(attrs['asyncFormValidator']), options = parseOptions(scope, attrs); | ||
ctrls[1].setup(function (model, _scope, _options) { | ||
addValidators(validateExpr, AsyncValidator, model, _scope, $q, _options); | ||
var validateExpr = scope.$eval(attrs['asyncFormValidator']), asyncValidatorCtrl = ctrls[1]; | ||
asyncValidatorCtrl.setup(function (model, _scope, $attrs) { | ||
addValidators(validateExpr, AsyncValidator, model, _scope, $q, $attrs); | ||
}); | ||
angular.forEach(ctrls[0], function (model, key) { | ||
if (angular.isObject(model) && key.charAt(0) !== '$') { | ||
ctrls[1].add(model, scope, options); | ||
asyncValidatorCtrl.add(model, scope, attrs); | ||
} | ||
}); | ||
scope.$on('$destroy', function () { | ||
ctrls[1].$pending.length = 0; | ||
ctrls[1].callback = null; | ||
asyncValidatorCtrl.$pending.length = 0; | ||
asyncValidatorCtrl.callback = null; | ||
}); | ||
@@ -283,4 +282,5 @@ }; | ||
} | ||
AsyncValidatorAdd.prototype.link = function (scope, el, attr, ctrls) { | ||
ctrls[1].add(ctrls[0], scope, parseOptions(scope, attr)); | ||
AsyncValidatorAdd.prototype.link = function (scope, el, attrs, ctrls) { | ||
var ngModel = ctrls[0], asyncValidatorCtrl = ctrls[1]; | ||
asyncValidatorCtrl.add(ngModel, scope, attrs); | ||
}; | ||
@@ -303,3 +303,3 @@ AsyncValidatorAdd.instance = function () { | ||
} | ||
addValidators(validateExpr, AsyncValidator, ctrl, scope, $q, parseOptions(scope, attrs)); | ||
addValidators(validateExpr, AsyncValidator, ctrl, scope, $q, attrs); | ||
var watches = []; | ||
@@ -306,0 +306,0 @@ function watchValues(watch) { |
@@ -13,28 +13,23 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.AsyncValidator = f()}})(function(){var define,module,exports;module={exports:(exports={})}; | ||
}); | ||
this.run = function (name, value, options) { | ||
this.run = function (name, value, options, returnValue) { | ||
if (typeof provider.validations[name] === 'undefined' || typeof provider.validations[name].validator !== 'function') { | ||
return $q.reject(name + ' isn\'t a registered async validator'); | ||
return $q.reject("" + name + " isn't a registered async validator"); | ||
} | ||
options = angular.extend({}, provider.validations[name].options.options, options); | ||
return new $q(function (resolve, reject) { | ||
try { | ||
resolve(provider.validations[name].validator(value, options)); | ||
} | ||
catch (e) { | ||
reject(e); | ||
} | ||
}).then(function (result) { | ||
return new $q(function asyncValidatorRunResolver(resolve) { | ||
resolve(provider.validations[name].validator(value, options)); | ||
}).then(function asyncValidatorResolved(result) { | ||
if (!!result) { | ||
return value; | ||
return returnValue === false ? true : value; | ||
} | ||
return $q.reject(); | ||
}, function (err) { | ||
}, function asyncValidatorRejected(e) { | ||
if (provider.validations[name].options.silentRejection) { | ||
return $q.reject(err); | ||
return $q.reject(e); | ||
} | ||
if (angular.isString(err)) { | ||
throw new Error(err); | ||
if (angular.isString(e)) { | ||
throw new Error(e); | ||
} | ||
else { | ||
throw err; | ||
throw e; | ||
} | ||
@@ -76,3 +71,4 @@ }); | ||
removeSync: true, | ||
silentRejection: true | ||
silentRejection: true, | ||
returnValue: true | ||
}; | ||
@@ -113,3 +109,3 @@ this.$get = Services.AsyncValidator.instance(this); | ||
angular.forEach(this.$pending, function (pending) { | ||
_this.add(pending.model, pending.scope, pending.options); | ||
_this.add(pending.model, pending.scope, pending.attrs); | ||
}); | ||
@@ -119,3 +115,3 @@ this.$pending.length = 0; | ||
}; | ||
AsyncForm.prototype.add = function (model, scope, options) { | ||
AsyncForm.prototype.add = function (model, scope, attrs) { | ||
if (!this.callback) { | ||
@@ -125,7 +121,7 @@ this.$pending.push({ | ||
scope: scope, | ||
options: options | ||
attrs: attrs | ||
}); | ||
return; | ||
} | ||
this.callback(model, scope, options); | ||
this.callback(model, scope, attrs); | ||
}; | ||
@@ -143,6 +139,9 @@ AsyncForm.$inject = []; | ||
angular.forEach(attrs.$attr, function (value, key) { | ||
if (!attrs[key]) { | ||
return; | ||
} | ||
var matches; | ||
if ((matches = value.match(optionsRegex))) { | ||
if (matches[1]) { | ||
if (typeof (evaled = scope.$eval(attrs[key])) === 'object') { | ||
if (angular.isObject(evaled = scope.$eval(attrs[key]))) { | ||
if (typeof opts[matches[1]] !== 'object') { | ||
@@ -155,3 +154,3 @@ opts[matches[1]] = {}; | ||
else { | ||
if (typeof (evaled = scope.$eval(attrs[key])) === 'object') { | ||
if (angular.isObject(evaled = scope.$eval(attrs[key]))) { | ||
angular.extend(opts['__'], evaled); | ||
@@ -164,3 +163,3 @@ } | ||
} | ||
function addValidators(validateExpr, AsyncValidator, ctrl, scope, $q, _options) { | ||
function addValidators(validateExpr, AsyncValidator, ctrl, scope, $q, $attrs) { | ||
if (angular.isString(validateExpr)) { | ||
@@ -179,3 +178,3 @@ if (AsyncValidator.validator(validateExpr)) { | ||
angular.forEach(validateExpr, function (exprssn, key) { | ||
var opts = AsyncValidator.options(key), modelOptions = _options['__'], validator = key; | ||
var opts = AsyncValidator.options(key), validator = key; | ||
if (angular.isString(exprssn) && angular.equals(opts, {})) { | ||
@@ -196,10 +195,10 @@ opts = AsyncValidator.options(exprssn); | ||
} | ||
else if (typeof _options[key] === 'object') { | ||
angular.extend(modelOptions, _options[key]); | ||
} | ||
if (typeof _options[validator] === 'object') { | ||
angular.extend(modelOptions, _options[validator]); | ||
} | ||
ctrl.$asyncValidators[key] = function validationFn(val) { | ||
var value; | ||
var value, _options = parseOptions(scope, $attrs), modelOptions = _options['__']; | ||
if (typeof _options[key] === 'object') { | ||
angular.extend(modelOptions, _options[key]); | ||
} | ||
if (typeof _options[validator] === 'object') { | ||
angular.extend(modelOptions, _options[validator]); | ||
} | ||
if (opts && opts.valueFrom === false) { | ||
@@ -221,3 +220,3 @@ value = ctrl; | ||
if (exprssn === '__VALIDATOR__' || exprssn === validator) { | ||
return AsyncValidator.run(validator, value, modelOptions); | ||
return AsyncValidator.run(validator, value, modelOptions, false); | ||
} | ||
@@ -255,14 +254,14 @@ else { | ||
this.link = function (scope, el, attrs, ctrls) { | ||
var validateExpr = scope.$eval(attrs['asyncFormValidator']), options = parseOptions(scope, attrs); | ||
ctrls[1].setup(function (model, _scope, _options) { | ||
addValidators(validateExpr, AsyncValidator, model, _scope, $q, _options); | ||
var validateExpr = scope.$eval(attrs['asyncFormValidator']), asyncValidatorCtrl = ctrls[1]; | ||
asyncValidatorCtrl.setup(function (model, _scope, $attrs) { | ||
addValidators(validateExpr, AsyncValidator, model, _scope, $q, $attrs); | ||
}); | ||
angular.forEach(ctrls[0], function (model, key) { | ||
if (angular.isObject(model) && key.charAt(0) !== '$') { | ||
ctrls[1].add(model, scope, options); | ||
asyncValidatorCtrl.add(model, scope, attrs); | ||
} | ||
}); | ||
scope.$on('$destroy', function () { | ||
ctrls[1].$pending.length = 0; | ||
ctrls[1].callback = null; | ||
asyncValidatorCtrl.$pending.length = 0; | ||
asyncValidatorCtrl.callback = null; | ||
}); | ||
@@ -284,4 +283,5 @@ }; | ||
} | ||
AsyncValidatorAdd.prototype.link = function (scope, el, attr, ctrls) { | ||
ctrls[1].add(ctrls[0], scope, parseOptions(scope, attr)); | ||
AsyncValidatorAdd.prototype.link = function (scope, el, attrs, ctrls) { | ||
var ngModel = ctrls[0], asyncValidatorCtrl = ctrls[1]; | ||
asyncValidatorCtrl.add(ngModel, scope, attrs); | ||
}; | ||
@@ -304,3 +304,3 @@ AsyncValidatorAdd.instance = function () { | ||
} | ||
addValidators(validateExpr, AsyncValidator, ctrl, scope, $q, parseOptions(scope, attrs)); | ||
addValidators(validateExpr, AsyncValidator, ctrl, scope, $q, attrs); | ||
var watches = []; | ||
@@ -307,0 +307,0 @@ function watchValues(watch) { |
{ | ||
"name": "angular-async-validator", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"homepage": "https://github.com/pocesar/angular-async-validator", | ||
@@ -5,0 +5,0 @@ "authors": [ |
{ | ||
"name": "angular-async-validator", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "This module enables you to register your own validation rules, or overwrite existing ones. Makes every validation 'promise based', so it can deal with both synchronous and asynchronous validations. Also, sometimes you want validate an entire form when a model changes, which currently there are no good ways to do this, hence this module, because validation and form manipulation in Angular 1.x is a pain by itself.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
[![Build Status](https://travis-ci.org/pocesar/angular-async-validator.svg?branch=master)](https://travis-ci.org/pocesar/angular-async-validator) [![Coverage Status](https://coveralls.io/repos/pocesar/angular-async-validator/badge.svg)](https://coveralls.io/r/pocesar/angular-async-validator) | ||
[![NPM](https://nodei.co/npm/angular-async-validator.png)](https://nodei.co/npm/angular-async-validator/) | ||
Angular Async Validator | ||
@@ -13,4 +15,8 @@ ===== | ||
This module requires Angular 1.3+ | ||
This module requires Angular 1.3+, and has no dependencies other than Angular itself. | ||
It also supports 3rd party promise libraries such as RSVP, Q, Bluebird, etc. | ||
[DEMO](http://plnkr.co/edit/jIhkAPShgK4ggRYN4N1S?p=preview) | ||
## Motivation | ||
@@ -17,0 +23,0 @@ |
@@ -26,3 +26,9 @@ describe('AsyncValidator', function () { | ||
afterEach(function(){ | ||
if ($exceptionHandler.fn.restore) { | ||
$exceptionHandler.fn.restore(); | ||
} | ||
}); | ||
function input(inputHtml) { | ||
@@ -116,3 +122,3 @@ var | ||
}; | ||
}, { silentRejection: false }); | ||
}); | ||
@@ -163,4 +169,3 @@ expect(function(){ | ||
expect($exceptionHandler.fn.callCount).to.equal(2); | ||
expect($exceptionHandler.fn.args[1][0].message).to.equal('ok'); | ||
$exceptionHandler.fn.restore(); | ||
expect(err).to.equal('ok'); | ||
done(); | ||
@@ -359,3 +364,2 @@ }); | ||
expect($exceptionHandler.fn.args[0][0]).to.match(/uhoh/); | ||
$exceptionHandler.fn.restore(); | ||
}); | ||
@@ -393,3 +397,2 @@ | ||
expect(el.controller().$asyncValidators).to.deep.equal({}); | ||
$exceptionHandler.fn.restore(); | ||
}); | ||
@@ -539,3 +542,59 @@ | ||
it('can use the same validator many times with different options', function(){ | ||
var spy = sinon.spy(); | ||
Provider.register('reuseValidator', function(){ | ||
return function($model, options) { | ||
spy($model.$viewValue, options.mode); | ||
switch (options.mode) { | ||
case 'number': | ||
return /^[0-9]+$/.test($model.$viewValue); | ||
case 'object': | ||
try { | ||
return angular.isObject(JSON.parse($model.$viewValue)); | ||
} catch (e) { | ||
return false; | ||
} | ||
case 'boolean': | ||
return !!$model.$viewValue; | ||
} | ||
return true; // never fail the base validator | ||
}; | ||
}); | ||
$scope['options'] = { | ||
number: { mode: 'number' }, | ||
object: { mode: 'object' }, | ||
boolean: { mode: 'boolean' }, | ||
}; | ||
var el = input('<input ng-model="data.n6" async-validator-options-boolean="options.boolean" async-validator-options-object="options.object" async-validator-options-number="options.number" async-validator="{number: \'reuseValidator\', object: \'reuseValidator\', boolean: \'reuseValidator\'}">'); | ||
el.compiled($scope); | ||
$scope.$digest(); | ||
expect(spy.args[0]).to.deep.equal([$scope.data.n6, 'number']); | ||
expect(spy.args[1]).to.deep.equal([$scope.data.n6, 'object']); | ||
expect(spy.args[2]).to.deep.equal([$scope.data.n6, 'boolean']); | ||
expect(el.controller()).to.have.deep.property('$error.number', true); | ||
expect(el.controller()).to.not.have.deep.property('$error.boolean'); | ||
expect(el.controller()).to.have.deep.property('$error.object', true); | ||
$scope.data.n6 = '{}'; | ||
$scope.$digest(); | ||
expect(el.controller()).to.have.deep.property('$error.number', true); | ||
expect(el.controller()).to.not.have.deep.property('$error.boolean'); | ||
expect(el.controller()).to.not.have.deep.property('$error.object'); | ||
$scope.data.n6 = '10'; | ||
$scope.$digest(); | ||
expect(el.controller()).to.not.have.deep.property('$error.number'); | ||
expect(el.controller()).to.not.have.deep.property('$error.boolean'); | ||
expect(el.controller()).to.have.deep.property('$error.object', true); | ||
}); | ||
}); | ||
@@ -542,0 +601,0 @@ }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
72809
1331
258