| 
									
										
										
										
											2016-06-23 09:47:54 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 10:15:17 -07:00
										 |  |  | import {InjectionToken, ɵisObservable as isObservable, ɵisPromise as isPromise, ɵmerge as merge} from '@angular/core'; | 
					
						
							|  |  |  | import {Observable} from 'rxjs/Observable'; | 
					
						
							|  |  |  | import {forkJoin} from 'rxjs/observable/forkJoin'; | 
					
						
							|  |  |  | import {fromPromise} from 'rxjs/observable/fromPromise'; | 
					
						
							|  |  |  | import {map} from 'rxjs/operator/map'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-03 16:54:46 -08:00
										 |  |  | import {AsyncValidatorFn, Validator, ValidatorFn} from './directives/validators'; | 
					
						
							| 
									
										
										
										
											2017-01-22 16:13:47 +13:00
										 |  |  | import {AbstractControl, FormControl, FormGroup} from './model'; | 
					
						
							| 
									
										
										
										
											2016-09-18 15:55:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-05 20:25:20 +03:00
										 |  |  | function isEmptyInputValue(value: any): boolean { | 
					
						
							|  |  |  |   // we don't check for string here so it also works with arrays
 | 
					
						
							|  |  |  |   return value == null || value.length === 0; | 
					
						
							| 
									
										
										
										
											2016-10-10 18:17:45 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-02 15:53:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |  * Providers for validators to be used for {@link FormControl}s in a form. | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Provide this using `multi: true` to add validators. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ### Example | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * {@example core/forms/ts/ng_validators/ng_validators.ts region='ng_validators'} | 
					
						
							| 
									
										
										
										
											2016-08-17 07:44:39 -07:00
										 |  |  |  * @stable | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-01-03 16:54:46 -08:00
										 |  |  | export const NG_VALIDATORS = new InjectionToken<Array<Validator|Function>>('NgValidators'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |  * Providers for asynchronous validators to be used for {@link FormControl}s | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |  * in a form. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Provide this using `multi: true` to add validators. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See {@link NG_VALIDATORS} for more details. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-08-17 07:44:39 -07:00
										 |  |  |  * @stable | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-01-03 16:54:46 -08:00
										 |  |  | export const NG_ASYNC_VALIDATORS = | 
					
						
							|  |  |  |     new InjectionToken<Array<Validator|Function>>('NgAsyncValidators'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-29 20:07:02 +03:00
										 |  |  | const EMAIL_REGEXP = | 
					
						
							|  |  |  |     /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Provides a set of validators used by form controls. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |  * A validator is a function that processes a {@link FormControl} or collection of | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |  * controls and returns a map of errors. A null map means that validation has passed. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ### Example | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ```typescript
 | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |  * var loginControl = new FormControl("", Validators.required) | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |  * ```
 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-08-17 07:44:39 -07:00
										 |  |  |  * @stable | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | export class Validators { | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Validator that requires controls to have a non-empty value. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-06-22 14:56:10 -07:00
										 |  |  |   static required(control: AbstractControl): {[key: string]: boolean} { | 
					
						
							| 
									
										
										
										
											2016-10-10 18:17:45 +02:00
										 |  |  |     return isEmptyInputValue(control.value) ? {'required': true} : null; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Validator that requires control value to be true. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   static requiredTrue(control: AbstractControl): {[key: string]: boolean} { | 
					
						
							|  |  |  |     return control.value === true ? null : {'required': true}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-29 20:07:02 +03:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Validator that performs email validation. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   static email(control: AbstractControl): {[key: string]: boolean} { | 
					
						
							|  |  |  |     return EMAIL_REGEXP.test(control.value) ? null : {'email': true}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Validator that requires controls to have a value of a minimum length. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   static minLength(minLength: number): ValidatorFn { | 
					
						
							| 
									
										
										
										
											2016-06-22 14:56:10 -07:00
										 |  |  |     return (control: AbstractControl): {[key: string]: any} => { | 
					
						
							| 
									
										
										
										
											2016-10-10 18:17:45 +02:00
										 |  |  |       if (isEmptyInputValue(control.value)) { | 
					
						
							|  |  |  |         return null;  // don't validate empty values to allow optional controls
 | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-12-12 22:17:12 +03:00
										 |  |  |       const length: number = control.value ? control.value.length : 0; | 
					
						
							| 
									
										
										
										
											2016-10-07 00:12:09 +02:00
										 |  |  |       return length < minLength ? | 
					
						
							|  |  |  |           {'minlength': {'requiredLength': minLength, 'actualLength': length}} : | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           null; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Validator that requires controls to have a value of a maximum length. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   static maxLength(maxLength: number): ValidatorFn { | 
					
						
							| 
									
										
										
										
											2016-06-22 14:56:10 -07:00
										 |  |  |     return (control: AbstractControl): {[key: string]: any} => { | 
					
						
							| 
									
										
										
										
											2016-12-12 22:17:12 +03:00
										 |  |  |       const length: number = control.value ? control.value.length : 0; | 
					
						
							| 
									
										
										
										
											2016-10-07 00:12:09 +02:00
										 |  |  |       return length > maxLength ? | 
					
						
							|  |  |  |           {'maxlength': {'requiredLength': maxLength, 'actualLength': length}} : | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           null; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Validator that requires a control to match a regex to its value. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-10-19 19:37:54 +03:00
										 |  |  |   static pattern(pattern: string|RegExp): ValidatorFn { | 
					
						
							|  |  |  |     if (!pattern) return Validators.nullValidator; | 
					
						
							|  |  |  |     let regex: RegExp; | 
					
						
							|  |  |  |     let regexStr: string; | 
					
						
							|  |  |  |     if (typeof pattern === 'string') { | 
					
						
							|  |  |  |       regexStr = `^${pattern}$`; | 
					
						
							|  |  |  |       regex = new RegExp(regexStr); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       regexStr = pattern.toString(); | 
					
						
							|  |  |  |       regex = pattern; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-22 14:56:10 -07:00
										 |  |  |     return (control: AbstractControl): {[key: string]: any} => { | 
					
						
							| 
									
										
										
										
											2016-10-10 18:17:45 +02:00
										 |  |  |       if (isEmptyInputValue(control.value)) { | 
					
						
							|  |  |  |         return null;  // don't validate empty values to allow optional controls
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const value: string = control.value; | 
					
						
							| 
									
										
										
										
											2016-10-19 19:37:54 +03:00
										 |  |  |       return regex.test(value) ? null : | 
					
						
							|  |  |  |                                  {'pattern': {'requiredPattern': regexStr, 'actualValue': value}}; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * No-op validator. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-06-22 14:56:10 -07:00
										 |  |  |   static nullValidator(c: AbstractControl): {[key: string]: boolean} { return null; } | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Compose multiple validators into a single function that returns the union | 
					
						
							|  |  |  |    * of the individual error maps. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   static compose(validators: ValidatorFn[]): ValidatorFn { | 
					
						
							| 
									
										
										
										
											2016-09-30 09:26:53 -07:00
										 |  |  |     if (!validators) return null; | 
					
						
							| 
									
										
										
										
											2016-10-19 19:37:54 +03:00
										 |  |  |     const presentValidators = validators.filter(isPresent); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     if (presentValidators.length == 0) return null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-22 14:56:10 -07:00
										 |  |  |     return function(control: AbstractControl) { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       return _mergeErrors(_executeValidators(control, presentValidators)); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn { | 
					
						
							| 
									
										
										
										
											2016-09-30 09:26:53 -07:00
										 |  |  |     if (!validators) return null; | 
					
						
							| 
									
										
										
										
											2016-10-19 19:37:54 +03:00
										 |  |  |     const presentValidators = validators.filter(isPresent); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     if (presentValidators.length == 0) return null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-22 14:56:10 -07:00
										 |  |  |     return function(control: AbstractControl) { | 
					
						
							| 
									
										
										
										
											2017-03-16 10:15:17 -07:00
										 |  |  |       const observables = _executeAsyncValidators(control, presentValidators).map(toObservable); | 
					
						
							|  |  |  |       return map.call(forkJoin(observables), _mergeErrors); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-02 09:37:01 -08:00
										 |  |  | function isPresent(o: any): boolean { | 
					
						
							|  |  |  |   return o != null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 10:15:17 -07:00
										 |  |  | export function toObservable(r: any): Observable<any> { | 
					
						
							|  |  |  |   const obs = isPromise(r) ? fromPromise(r) : r; | 
					
						
							|  |  |  |   if (!(isObservable(obs))) { | 
					
						
							|  |  |  |     throw new Error(`Expected validator to return Promise or Observable.`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return obs; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-22 14:56:10 -07:00
										 |  |  | function _executeValidators(control: AbstractControl, validators: ValidatorFn[]): any[] { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |   return validators.map(v => v(control)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-22 14:56:10 -07:00
										 |  |  | function _executeAsyncValidators(control: AbstractControl, validators: AsyncValidatorFn[]): any[] { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |   return validators.map(v => v(control)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _mergeErrors(arrayOfErrors: any[]): {[key: string]: any} { | 
					
						
							| 
									
										
										
										
											2016-10-19 19:37:54 +03:00
										 |  |  |   const res: {[key: string]: any} = | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       arrayOfErrors.reduce((res: {[key: string]: any}, errors: {[key: string]: any}) => { | 
					
						
							| 
									
										
										
										
											2017-03-02 09:37:01 -08:00
										 |  |  |         return errors != null ? merge(res, errors) : res; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }, {}); | 
					
						
							| 
									
										
										
										
											2016-10-03 16:46:05 -07:00
										 |  |  |   return Object.keys(res).length === 0 ? null : res; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | } |