mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-18 15:50:22 +00:00
Minor documentation fixes. Should not be any code changes. One test changed due to dependency on text in documentation.
483 lines
16 KiB
JavaScript
483 lines
16 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc overview
|
|
* @name angular.validator
|
|
* @description
|
|
*
|
|
* Most of the built-in angular validators are used to check user input against defined types or
|
|
* patterns. You can easily create your own custom validators as well.
|
|
*
|
|
* Following is the list of built-in angular validators:
|
|
*
|
|
* * {@link angular.validator.asynchronous asynchronous()} - Provides asynchronous validation via a
|
|
* callback function.
|
|
* * {@link angular.validator.date date()} - Checks user input against default date format:
|
|
* "MM/DD/YYYY"
|
|
* * {@link angular.validator.email email()} - Validates that user input is a well-formed email
|
|
* address.
|
|
* * {@link angular.validator.integer integer()} - Validates that user input is an integer
|
|
* * {@link angular.validator.json json()} - Validates that user input is valid JSON
|
|
* * {@link angular.validator.number number()} - Validates that user input is a number
|
|
* * {@link angular.validator.phone phone()} - Validates that user input matches the pattern
|
|
* "1(123)123-1234"
|
|
* * {@link angular.validator.regexp regexp()} - Restricts valid input to a specified regular
|
|
* expression pattern
|
|
* * {@link angular.validator.url url()} - Validates that user input is a well-formed URL.
|
|
*
|
|
* For more information about how angular validators work, and how to create your own validators,
|
|
* see {@link guide/dev_guide.templates.validators Understanding Angular Validators} in the angular
|
|
* Developer Guide.
|
|
*/
|
|
|
|
extend(angularValidator, {
|
|
'noop': function() { return null; },
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc validator
|
|
* @name angular.validator.regexp
|
|
* @description
|
|
* Use regexp validator to restrict the input to any Regular Expression.
|
|
*
|
|
* @param {string} value value to validate
|
|
* @param {string|regexp} expression regular expression.
|
|
* @param {string=} msg error message to display.
|
|
* @css ng-validation-error
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
<script> function Cntl(){
|
|
this.ssnRegExp = /^\d\d\d-\d\d-\d\d\d\d$/;
|
|
}
|
|
</script>
|
|
Enter valid SSN:
|
|
<div ng:controller="Cntl">
|
|
<input name="ssn" value="123-45-6789" ng:validate="regexp:ssnRegExp" >
|
|
</div>
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should invalidate non ssn', function(){
|
|
var textBox = element('.doc-example-live :input');
|
|
expect(textBox.attr('className')).not().toMatch(/ng-validation-error/);
|
|
expect(textBox.val()).toEqual('123-45-6789');
|
|
input('ssn').enter('123-45-67890');
|
|
expect(textBox.attr('className')).toMatch(/ng-validation-error/);
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*
|
|
*/
|
|
'regexp': function(value, regexp, msg) {
|
|
if (!value.match(regexp)) {
|
|
return msg ||
|
|
"Value does not match expected format " + regexp + ".";
|
|
} else {
|
|
return null;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc validator
|
|
* @name angular.validator.number
|
|
* @description
|
|
* Use number validator to restrict the input to numbers with an
|
|
* optional range. (See integer for whole numbers validator).
|
|
*
|
|
* @param {string} value value to validate
|
|
* @param {int=} [min=MIN_INT] minimum value.
|
|
* @param {int=} [max=MAX_INT] maximum value.
|
|
* @css ng-validation-error
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
Enter number: <input name="n1" ng:validate="number" > <br>
|
|
Enter number greater than 10: <input name="n2" ng:validate="number:10" > <br>
|
|
Enter number between 100 and 200: <input name="n3" ng:validate="number:100:200" > <br>
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should invalidate number', function(){
|
|
var n1 = element('.doc-example-live :input[name=n1]');
|
|
expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('n1').enter('1.x');
|
|
expect(n1.attr('className')).toMatch(/ng-validation-error/);
|
|
var n2 = element('.doc-example-live :input[name=n2]');
|
|
expect(n2.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('n2').enter('9');
|
|
expect(n2.attr('className')).toMatch(/ng-validation-error/);
|
|
var n3 = element('.doc-example-live :input[name=n3]');
|
|
expect(n3.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('n3').enter('201');
|
|
expect(n3.attr('className')).toMatch(/ng-validation-error/);
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*
|
|
*/
|
|
'number': function(value, min, max) {
|
|
var num = 1 * value;
|
|
if (num == value) {
|
|
if (typeof min != $undefined && num < min) {
|
|
return "Value can not be less than " + min + ".";
|
|
}
|
|
if (typeof min != $undefined && num > max) {
|
|
return "Value can not be greater than " + max + ".";
|
|
}
|
|
return null;
|
|
} else {
|
|
return "Not a number";
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc validator
|
|
* @name angular.validator.integer
|
|
* @description
|
|
* Use number validator to restrict the input to integers with an
|
|
* optional range. (See integer for whole numbers validator).
|
|
*
|
|
* @param {string} value value to validate
|
|
* @param {int=} [min=MIN_INT] minimum value.
|
|
* @param {int=} [max=MAX_INT] maximum value.
|
|
* @css ng-validation-error
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
Enter integer: <input name="n1" ng:validate="integer" > <br>
|
|
Enter integer equal or greater than 10: <input name="n2" ng:validate="integer:10" > <br>
|
|
Enter integer between 100 and 200 (inclusive): <input name="n3" ng:validate="integer:100:200" > <br>
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should invalidate integer', function(){
|
|
var n1 = element('.doc-example-live :input[name=n1]');
|
|
expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('n1').enter('1.1');
|
|
expect(n1.attr('className')).toMatch(/ng-validation-error/);
|
|
var n2 = element('.doc-example-live :input[name=n2]');
|
|
expect(n2.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('n2').enter('10.1');
|
|
expect(n2.attr('className')).toMatch(/ng-validation-error/);
|
|
var n3 = element('.doc-example-live :input[name=n3]');
|
|
expect(n3.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('n3').enter('100.1');
|
|
expect(n3.attr('className')).toMatch(/ng-validation-error/);
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*/
|
|
'integer': function(value, min, max) {
|
|
var numberError = angularValidator['number'](value, min, max);
|
|
if (numberError) return numberError;
|
|
if (!("" + value).match(/^\s*[\d+]*\s*$/) || value != Math.round(value)) {
|
|
return "Not a whole number";
|
|
}
|
|
return null;
|
|
},
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc validator
|
|
* @name angular.validator.date
|
|
* @description
|
|
* Use date validator to restrict the user input to a valid date
|
|
* in format in format MM/DD/YYYY.
|
|
*
|
|
* @param {string} value value to validate
|
|
* @css ng-validation-error
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
Enter valid date:
|
|
<input name="text" value="1/1/2009" ng:validate="date" >
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should invalidate date', function(){
|
|
var n1 = element('.doc-example-live :input');
|
|
expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('text').enter('123/123/123');
|
|
expect(n1.attr('className')).toMatch(/ng-validation-error/);
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*
|
|
*/
|
|
'date': function(value) {
|
|
var fields = /^(\d\d?)\/(\d\d?)\/(\d\d\d\d)$/.exec(value);
|
|
var date = fields ? new Date(fields[3], fields[1]-1, fields[2]) : 0;
|
|
return (date &&
|
|
date.getFullYear() == fields[3] &&
|
|
date.getMonth() == fields[1]-1 &&
|
|
date.getDate() == fields[2])
|
|
? null
|
|
: "Value is not a date. (Expecting format: 12/31/2009).";
|
|
},
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc validator
|
|
* @name angular.validator.email
|
|
* @description
|
|
* Use email validator if you wist to restrict the user input to a valid email.
|
|
*
|
|
* @param {string} value value to validate
|
|
* @css ng-validation-error
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
Enter valid email:
|
|
<input name="text" ng:validate="email" value="me@example.com">
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should invalidate email', function(){
|
|
var n1 = element('.doc-example-live :input');
|
|
expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('text').enter('a@b.c');
|
|
expect(n1.attr('className')).toMatch(/ng-validation-error/);
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*
|
|
*/
|
|
'email': function(value) {
|
|
if (value.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/)) {
|
|
return null;
|
|
}
|
|
return "Email needs to be in username@host.com format.";
|
|
},
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc validator
|
|
* @name angular.validator.phone
|
|
* @description
|
|
* Use phone validator to restrict the input phone numbers.
|
|
*
|
|
* @param {string} value value to validate
|
|
* @css ng-validation-error
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
Enter valid phone number:
|
|
<input name="text" value="1(234)567-8901" ng:validate="phone" >
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should invalidate phone', function(){
|
|
var n1 = element('.doc-example-live :input');
|
|
expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('text').enter('+12345678');
|
|
expect(n1.attr('className')).toMatch(/ng-validation-error/);
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*
|
|
*/
|
|
'phone': function(value) {
|
|
if (value.match(/^1\(\d\d\d\)\d\d\d-\d\d\d\d$/)) {
|
|
return null;
|
|
}
|
|
if (value.match(/^\+\d{2,3} (\(\d{1,5}\))?[\d ]+\d$/)) {
|
|
return null;
|
|
}
|
|
return "Phone number needs to be in 1(987)654-3210 format in North America " +
|
|
"or +999 (123) 45678 906 internationally.";
|
|
},
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc validator
|
|
* @name angular.validator.url
|
|
* @description
|
|
* Use phone validator to restrict the input URLs.
|
|
*
|
|
* @param {string} value value to validate
|
|
* @css ng-validation-error
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
Enter valid URL:
|
|
<input name="text" value="http://example.com/abc.html" size="40" ng:validate="url" >
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should invalidate url', function(){
|
|
var n1 = element('.doc-example-live :input');
|
|
expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('text').enter('abc://server/path');
|
|
expect(n1.attr('className')).toMatch(/ng-validation-error/);
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*
|
|
*/
|
|
'url': function(value) {
|
|
if (value.match(/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/)) {
|
|
return null;
|
|
}
|
|
return "URL needs to be in http://server[:port]/path format.";
|
|
},
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc validator
|
|
* @name angular.validator.json
|
|
* @description
|
|
* Use json validator if you wish to restrict the user input to a valid JSON.
|
|
*
|
|
* @param {string} value value to validate
|
|
* @css ng-validation-error
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
<textarea name="json" cols="60" rows="5" ng:validate="json">
|
|
{name:'abc'}
|
|
</textarea>
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should invalidate json', function(){
|
|
var n1 = element('.doc-example-live :input');
|
|
expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('json').enter('{name}');
|
|
expect(n1.attr('className')).toMatch(/ng-validation-error/);
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*
|
|
*/
|
|
'json': function(value) {
|
|
try {
|
|
fromJson(value);
|
|
return null;
|
|
} catch (e) {
|
|
return e.toString();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @workInProgress
|
|
* @ngdoc validator
|
|
* @name angular.validator.asynchronous
|
|
* @description
|
|
* Use asynchronous validator if the validation can not be computed
|
|
* immediately, but is provided through a callback. The widget
|
|
* automatically shows a spinning indicator while the validity of
|
|
* the widget is computed. This validator caches the result.
|
|
*
|
|
* @param {string} value value to validate
|
|
* @param {function(inputToValidate,validationDone)} validate function to call to validate the state
|
|
* of the input.
|
|
* @param {function(data)=} [update=noop] function to call when state of the
|
|
* validator changes
|
|
*
|
|
* @paramDescription
|
|
* The `validate` function (specified by you) is called as
|
|
* `validate(inputToValidate, validationDone)`:
|
|
*
|
|
* * `inputToValidate`: value of the input box.
|
|
* * `validationDone`: `function(error, data){...}`
|
|
* * `error`: error text to display if validation fails
|
|
* * `data`: data object to pass to update function
|
|
*
|
|
* The `update` function is optionally specified by you and is
|
|
* called by <angular/> on input change. Since the
|
|
* asynchronous validator caches the results, the update
|
|
* function can be called without a call to `validate`
|
|
* function. The function is called as `update(data)`:
|
|
*
|
|
* * `data`: data object as passed from validate function
|
|
*
|
|
* @css ng-input-indicator-wait, ng-validation-error
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
<script>
|
|
function MyCntl(){
|
|
this.myValidator = function (inputToValidate, validationDone) {
|
|
setTimeout(function(){
|
|
validationDone(inputToValidate.length % 2);
|
|
}, 500);
|
|
}
|
|
}
|
|
</script>
|
|
This input is validated asynchronously:
|
|
<div ng:controller="MyCntl">
|
|
<input name="text" ng:validate="asynchronous:myValidator">
|
|
</div>
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should change color in delayed way', function(){
|
|
var textBox = element('.doc-example-live :input');
|
|
expect(textBox.attr('className')).not().toMatch(/ng-input-indicator-wait/);
|
|
expect(textBox.attr('className')).not().toMatch(/ng-validation-error/);
|
|
input('text').enter('X');
|
|
expect(textBox.attr('className')).toMatch(/ng-input-indicator-wait/);
|
|
sleep(.6);
|
|
expect(textBox.attr('className')).not().toMatch(/ng-input-indicator-wait/);
|
|
expect(textBox.attr('className')).toMatch(/ng-validation-error/);
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*
|
|
*/
|
|
/*
|
|
* cache is attached to the element
|
|
* cache: {
|
|
* inputs : {
|
|
* 'user input': {
|
|
* response: server response,
|
|
* error: validation error
|
|
* },
|
|
* current: 'current input'
|
|
* }
|
|
* }
|
|
*
|
|
*/
|
|
'asynchronous': function(input, asynchronousFn, updateFn) {
|
|
if (!input) return;
|
|
var scope = this;
|
|
var element = scope.$element;
|
|
var cache = element.data('$asyncValidator');
|
|
if (!cache) {
|
|
element.data('$asyncValidator', cache = {inputs:{}});
|
|
}
|
|
|
|
cache.current = input;
|
|
|
|
var inputState = cache.inputs[input],
|
|
$invalidWidgets = scope.$service('$invalidWidgets');
|
|
|
|
if (!inputState) {
|
|
cache.inputs[input] = inputState = { inFlight: true };
|
|
$invalidWidgets.markInvalid(scope.$element);
|
|
element.addClass('ng-input-indicator-wait');
|
|
asynchronousFn(input, function(error, data) {
|
|
inputState.response = data;
|
|
inputState.error = error;
|
|
inputState.inFlight = false;
|
|
if (cache.current == input) {
|
|
element.removeClass('ng-input-indicator-wait');
|
|
$invalidWidgets.markValid(element);
|
|
}
|
|
element.data($$validate)();
|
|
scope.$service('$updateView')();
|
|
});
|
|
} else if (inputState.inFlight) {
|
|
// request in flight, mark widget invalid, but don't show it to user
|
|
$invalidWidgets.markInvalid(scope.$element);
|
|
} else {
|
|
(updateFn||noop)(inputState.response);
|
|
}
|
|
return inputState.error;
|
|
}
|
|
|
|
});
|