2015-10-29 17:45:24 -07:00
|
|
|
import {isBlank, isPresent, CONST_EXPR} from 'angular2/src/core/facade/lang';
|
2015-11-05 14:58:24 -08:00
|
|
|
import {PromiseWrapper} from 'angular2/src/core/facade/promise';
|
2015-11-05 17:18:16 -08:00
|
|
|
import {ObservableWrapper} from 'angular2/src/core/facade/async';
|
2015-08-28 11:29:19 -07:00
|
|
|
import {ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
2015-09-03 22:01:36 -07:00
|
|
|
import {OpaqueToken} from 'angular2/src/core/di';
|
2015-02-11 11:10:31 -08:00
|
|
|
|
2015-03-09 17:41:49 +01:00
|
|
|
import * as modelModule from './model';
|
2015-02-11 11:10:31 -08:00
|
|
|
|
2015-09-29 12:59:56 -07:00
|
|
|
/**
|
|
|
|
* Providers for validators to be used for {@link Control}s in a form.
|
|
|
|
*
|
|
|
|
* Provide this using `multi: true` to add validators.
|
|
|
|
*
|
|
|
|
* ### Example
|
|
|
|
*
|
|
|
|
* ```typescript
|
|
|
|
* var providers = [
|
|
|
|
* new Provider(NG_VALIDATORS, {useValue: myValidator, multi: true})
|
|
|
|
* ];
|
|
|
|
* ```
|
|
|
|
*/
|
2015-09-03 08:14:51 -07:00
|
|
|
export const NG_VALIDATORS: OpaqueToken = CONST_EXPR(new OpaqueToken("NgValidators"));
|
2015-11-02 09:59:40 -08:00
|
|
|
export const NG_ASYNC_VALIDATORS: OpaqueToken = CONST_EXPR(new OpaqueToken("NgAsyncValidators"));
|
2015-09-02 10:24:22 -07:00
|
|
|
|
2015-03-31 22:47:11 +00:00
|
|
|
/**
|
2015-04-10 11:15:01 -07:00
|
|
|
* Provides a set of validators used by form controls.
|
|
|
|
*
|
2015-09-29 12:59:56 -07:00
|
|
|
* A validator is a function that processes a {@link Control} or collection of
|
|
|
|
* controls and returns a {@link StringMap} of errors. A null map means that
|
|
|
|
* validation has passed.
|
2015-04-10 11:15:01 -07:00
|
|
|
*
|
2015-09-29 12:59:56 -07:00
|
|
|
* # Example
|
|
|
|
*
|
|
|
|
* ```typescript
|
2015-04-10 11:15:01 -07:00
|
|
|
* var loginControl = new Control("", Validators.required)
|
|
|
|
* ```
|
2015-03-31 22:47:11 +00:00
|
|
|
*/
|
2015-03-19 14:21:40 -07:00
|
|
|
export class Validators {
|
2015-09-29 12:59:56 -07:00
|
|
|
/**
|
|
|
|
* Validator that requires controls to have a non-empty value.
|
|
|
|
*/
|
2015-10-02 16:47:54 -07:00
|
|
|
static required(control: modelModule.Control): {[key: string]: boolean} {
|
2015-09-01 20:59:43 -07:00
|
|
|
return isBlank(control.value) || control.value == "" ? {"required": true} : null;
|
2015-03-19 14:21:40 -07:00
|
|
|
}
|
2015-02-11 11:10:31 -08:00
|
|
|
|
2015-09-29 12:59:56 -07:00
|
|
|
/**
|
|
|
|
* Validator that requires controls to have a value of a minimum length.
|
|
|
|
*/
|
2015-10-13 14:38:13 -07:00
|
|
|
static minLength(minLength: number): Function {
|
|
|
|
return (control: modelModule.Control): {[key: string]: any} => {
|
|
|
|
if (isPresent(Validators.required(control))) return null;
|
|
|
|
var v: string = control.value;
|
|
|
|
return v.length < minLength ?
|
|
|
|
{"minlength": {"requiredLength": minLength, "actualLength": v.length}} :
|
|
|
|
null;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-09-29 12:59:56 -07:00
|
|
|
/**
|
|
|
|
* Validator that requires controls to have a value of a maximum length.
|
|
|
|
*/
|
2015-10-13 14:38:13 -07:00
|
|
|
static maxLength(maxLength: number): Function {
|
|
|
|
return (control: modelModule.Control): {[key: string]: any} => {
|
|
|
|
if (isPresent(Validators.required(control))) return null;
|
|
|
|
var v: string = control.value;
|
|
|
|
return v.length > maxLength ?
|
|
|
|
{"maxlength": {"requiredLength": maxLength, "actualLength": v.length}} :
|
|
|
|
null;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-09-29 12:59:56 -07:00
|
|
|
/**
|
|
|
|
* No-op validator.
|
|
|
|
*/
|
2015-10-02 16:47:54 -07:00
|
|
|
static nullValidator(c: any): {[key: string]: boolean} { return null; }
|
2015-02-11 11:10:31 -08:00
|
|
|
|
2015-09-29 12:59:56 -07:00
|
|
|
/**
|
|
|
|
* Compose multiple validators into a single function that returns the union
|
|
|
|
* of the individual error maps.
|
|
|
|
*/
|
2015-08-28 11:29:19 -07:00
|
|
|
static compose(validators: Function[]): Function {
|
2015-11-02 09:59:40 -08:00
|
|
|
if (isBlank(validators)) return null;
|
|
|
|
var presentValidators = ListWrapper.filter(validators, isPresent);
|
|
|
|
if (presentValidators.length == 0) return null;
|
2015-09-02 10:24:22 -07:00
|
|
|
|
feat(validators): Allow errors at both the group/array level or their children
Allow ControlGroups and ControlArrays to contain errors from their level, and
errors from their children. [Design Doc](https://docs.google.com/document/d/1EnJ3-_iFpVKFz1ifN1LkXSGQ7h3A72OQGry2g8eo7IA/edit?pli=1#heading=h.j53rt81eegm4)
BREAKING CHANGE: errors format has changed from validators. Now errors from
a control or an array's children are prefixed with 'controls' while errors
from the object itself are left at the root level.
Example:
Given a Control group as follows:
var group = new ControlGroup({
login: new Control("", required),
password: new Control("", required),
passwordConfirm: new Control("", required)
});
Before:
group.errors
{
login: {required: true},
password: {required: true},
passwordConfirm: {required: true},
}
After:
group.errors
{
controls: {
login: {required: true},
password: {required: true},
passwordConfirm: {required: true},
}
}
2015-10-16 16:13:14 -07:00
|
|
|
return function(control: modelModule.AbstractControl) {
|
2015-11-02 09:59:40 -08:00
|
|
|
return _mergeErrors(_executeValidators(control, presentValidators));
|
2015-07-15 12:12:23 -07:00
|
|
|
};
|
2015-03-19 14:21:40 -07:00
|
|
|
}
|
2015-11-02 09:59:40 -08:00
|
|
|
|
|
|
|
static composeAsync(validators: Function[]): Function {
|
|
|
|
if (isBlank(validators)) return null;
|
2015-11-05 17:18:16 -08:00
|
|
|
let presentValidators = ListWrapper.filter(validators, isPresent);
|
2015-11-02 09:59:40 -08:00
|
|
|
if (presentValidators.length == 0) return null;
|
|
|
|
|
|
|
|
return function(control: modelModule.AbstractControl) {
|
2015-11-05 17:18:16 -08:00
|
|
|
let promises = _executeValidators(control, presentValidators).map(_convertToPromise);
|
|
|
|
return PromiseWrapper.all(promises).then(_mergeErrors);
|
2015-11-02 09:59:40 -08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-05 17:18:16 -08:00
|
|
|
function _convertToPromise(obj: any): any {
|
|
|
|
return PromiseWrapper.isPromise(obj) ? obj : ObservableWrapper.toPromise(obj);
|
|
|
|
}
|
|
|
|
|
2015-11-02 09:59:40 -08:00
|
|
|
function _executeValidators(control: modelModule.AbstractControl, validators: Function[]): any[] {
|
|
|
|
return validators.map(v => v(control));
|
|
|
|
}
|
|
|
|
|
|
|
|
function _mergeErrors(arrayOfErrors: any[]): {[key: string]: any} {
|
|
|
|
var res = ListWrapper.reduce(arrayOfErrors, (res, errors) => {
|
|
|
|
return isPresent(errors) ? StringMapWrapper.merge(<any>res, <any>errors) : res;
|
|
|
|
}, {});
|
|
|
|
return StringMapWrapper.isEmpty(res) ? null : res;
|
2015-02-11 11:10:31 -08:00
|
|
|
}
|