/**
* @license Angular v8.1.0
* (c) 2010-2019 Google LLC. https://angular.io/
* License: MIT
*/
import { InjectionToken, forwardRef, Directive, Renderer2, ElementRef, Optional, Inject, Self, ɵisPromise, ɵisObservable, Injectable, Injector, Input, ɵlooseIdentical, Host, isDevMode, EventEmitter, SkipSelf, Output, NgModule, Version } from '@angular/core';
import { ɵgetDOM } from '@angular/platform-browser';
import { forkJoin, from } from 'rxjs';
import { map } from 'rxjs/operators';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Used to provide a `ControlValueAccessor` for form controls.
*
* See `DefaultValueAccessor` for how to implement one.
*
* \@publicApi
* @type {?}
*/
const NG_VALUE_ACCESSOR = new InjectionToken('NgValueAccessor');
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const CHECKBOX_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => CheckboxControlValueAccessor)),
multi: true,
};
/**
* \@description
* A `ControlValueAccessor` for writing a value and listening to changes on a checkbox input
* element.
*
* \@usageNotes
*
* ### Using a checkbox with a reactive form.
*
* The following example shows how to use a checkbox with a reactive form.
*
* ```ts
* const rememberLoginControl = new FormControl();
* ```
*
* ```
*
* ```
*
* \@ngModule ReactiveFormsModule
* \@ngModule FormsModule
* \@publicApi
*/
class CheckboxControlValueAccessor {
/**
* @param {?} _renderer
* @param {?} _elementRef
*/
constructor(_renderer, _elementRef) {
this._renderer = _renderer;
this._elementRef = _elementRef;
/**
* \@description
* The registered callback function called when a change event occurs on the input element.
*/
this.onChange = (/**
* @param {?} _
* @return {?}
*/
(_) => { });
/**
* \@description
* The registered callback function called when a blur event occurs on the input element.
*/
this.onTouched = (/**
* @return {?}
*/
() => { });
}
/**
* Sets the "checked" property on the input element.
*
* @param {?} value The checked value
* @return {?}
*/
writeValue(value) {
this._renderer.setProperty(this._elementRef.nativeElement, 'checked', value);
}
/**
* \@description
* Registers a function called when the control value changes.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnChange(fn) { this.onChange = fn; }
/**
* \@description
* Registers a function called when the control is touched.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnTouched(fn) { this.onTouched = fn; }
/**
* Sets the "disabled" property on the input element.
*
* @param {?} isDisabled The disabled value
* @return {?}
*/
setDisabledState(isDisabled) {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}
}
CheckboxControlValueAccessor.decorators = [
{ type: Directive, args: [{
selector: 'input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]',
host: { '(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()' },
providers: [CHECKBOX_VALUE_ACCESSOR]
},] }
];
/** @nocollapse */
CheckboxControlValueAccessor.ctorParameters = () => [
{ type: Renderer2 },
{ type: ElementRef }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const DEFAULT_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => DefaultValueAccessor)),
multi: true
};
/**
* We must check whether the agent is Android because composition events
* behave differently between iOS and Android.
* @return {?}
*/
function _isAndroid() {
/** @type {?} */
const userAgent = ɵgetDOM() ? ɵgetDOM().getUserAgent() : '';
return /android (\d+)/.test(userAgent.toLowerCase());
}
/**
* \@description
* Provide this token to control if form directives buffer IME input until
* the "compositionend" event occurs.
* \@publicApi
* @type {?}
*/
const COMPOSITION_BUFFER_MODE = new InjectionToken('CompositionEventMode');
/**
* \@description
* The default `ControlValueAccessor` for writing a value and listening to changes on input
* elements. The accessor is used by the `FormControlDirective`, `FormControlName`, and
* `NgModel` directives.
*
* \@usageNotes
*
* ### Using the default value accessor
*
* The following example shows how to use an input element that activates the default value accessor
* (in this case, a text field).
*
* ```ts
* const firstNameControl = new FormControl();
* ```
*
* ```
*
* ```
*
* \@ngModule ReactiveFormsModule
* \@ngModule FormsModule
* \@publicApi
*/
class DefaultValueAccessor {
/**
* @param {?} _renderer
* @param {?} _elementRef
* @param {?} _compositionMode
*/
constructor(_renderer, _elementRef, _compositionMode) {
this._renderer = _renderer;
this._elementRef = _elementRef;
this._compositionMode = _compositionMode;
/**
* \@description
* The registered callback function called when an input event occurs on the input element.
*/
this.onChange = (/**
* @param {?} _
* @return {?}
*/
(_) => { });
/**
* \@description
* The registered callback function called when a blur event occurs on the input element.
*/
this.onTouched = (/**
* @return {?}
*/
() => { });
/**
* Whether the user is creating a composition string (IME events).
*/
this._composing = false;
if (this._compositionMode == null) {
this._compositionMode = !_isAndroid();
}
}
/**
* Sets the "value" property on the input element.
*
* @param {?} value The checked value
* @return {?}
*/
writeValue(value) {
/** @type {?} */
const normalizedValue = value == null ? '' : value;
this._renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue);
}
/**
* \@description
* Registers a function called when the control value changes.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnChange(fn) { this.onChange = fn; }
/**
* \@description
* Registers a function called when the control is touched.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnTouched(fn) { this.onTouched = fn; }
/**
* Sets the "disabled" property on the input element.
*
* @param {?} isDisabled The disabled value
* @return {?}
*/
setDisabledState(isDisabled) {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}
/**
* \@internal
* @param {?} value
* @return {?}
*/
_handleInput(value) {
if (!this._compositionMode || (this._compositionMode && !this._composing)) {
this.onChange(value);
}
}
/**
* \@internal
* @return {?}
*/
_compositionStart() { this._composing = true; }
/**
* \@internal
* @param {?} value
* @return {?}
*/
_compositionEnd(value) {
this._composing = false;
this._compositionMode && this.onChange(value);
}
}
DefaultValueAccessor.decorators = [
{ type: Directive, args: [{
selector: 'input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]',
// TODO: vsavkin replace the above selector with the one below it once
// https://github.com/angular/angular/issues/3011 is implemented
// selector: '[ngModel],[formControl],[formControlName]',
host: {
'(input)': '$any(this)._handleInput($event.target.value)',
'(blur)': 'onTouched()',
'(compositionstart)': '$any(this)._compositionStart()',
'(compositionend)': '$any(this)._compositionEnd($event.target.value)'
},
providers: [DEFAULT_VALUE_ACCESSOR]
},] }
];
/** @nocollapse */
DefaultValueAccessor.ctorParameters = () => [
{ type: Renderer2 },
{ type: ElementRef },
{ type: Boolean, decorators: [{ type: Optional }, { type: Inject, args: [COMPOSITION_BUFFER_MODE,] }] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @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
*/
/**
* \@description
* Base class for control directives.
*
* This class is only used internally in the `ReactiveFormsModule` and the `FormsModule`.
*
* \@publicApi
* @abstract
*/
class AbstractControlDirective {
/**
* \@description
* Reports the value of the control if it is present, otherwise null.
* @return {?}
*/
get value() { return this.control ? this.control.value : null; }
/**
* \@description
* Reports whether the control is valid. A control is considered valid if no
* validation errors exist with the current value.
* If the control is not present, null is returned.
* @return {?}
*/
get valid() { return this.control ? this.control.valid : null; }
/**
* \@description
* Reports whether the control is invalid, meaning that an error exists in the input value.
* If the control is not present, null is returned.
* @return {?}
*/
get invalid() { return this.control ? this.control.invalid : null; }
/**
* \@description
* Reports whether a control is pending, meaning that that async validation is occurring and
* errors are not yet available for the input value. If the control is not present, null is
* returned.
* @return {?}
*/
get pending() { return this.control ? this.control.pending : null; }
/**
* \@description
* Reports whether the control is disabled, meaning that the control is disabled
* in the UI and is exempt from validation checks and excluded from aggregate
* values of ancestor controls. If the control is not present, null is returned.
* @return {?}
*/
get disabled() { return this.control ? this.control.disabled : null; }
/**
* \@description
* Reports whether the control is enabled, meaning that the control is included in ancestor
* calculations of validity or value. If the control is not present, null is returned.
* @return {?}
*/
get enabled() { return this.control ? this.control.enabled : null; }
/**
* \@description
* Reports the control's validation errors. If the control is not present, null is returned.
* @return {?}
*/
get errors() { return this.control ? this.control.errors : null; }
/**
* \@description
* Reports whether the control is pristine, meaning that the user has not yet changed
* the value in the UI. If the control is not present, null is returned.
* @return {?}
*/
get pristine() { return this.control ? this.control.pristine : null; }
/**
* \@description
* Reports whether the control is dirty, meaning that the user has changed
* the value in the UI. If the control is not present, null is returned.
* @return {?}
*/
get dirty() { return this.control ? this.control.dirty : null; }
/**
* \@description
* Reports whether the control is touched, meaning that the user has triggered
* a `blur` event on it. If the control is not present, null is returned.
* @return {?}
*/
get touched() { return this.control ? this.control.touched : null; }
/**
* \@description
* Reports the validation status of the control. Possible values include:
* 'VALID', 'INVALID', 'DISABLED', and 'PENDING'.
* If the control is not present, null is returned.
* @return {?}
*/
get status() { return this.control ? this.control.status : null; }
/**
* \@description
* Reports whether the control is untouched, meaning that the user has not yet triggered
* a `blur` event on it. If the control is not present, null is returned.
* @return {?}
*/
get untouched() { return this.control ? this.control.untouched : null; }
/**
* \@description
* Returns a multicasting observable that emits a validation status whenever it is
* calculated for the control. If the control is not present, null is returned.
* @return {?}
*/
get statusChanges() {
return this.control ? this.control.statusChanges : null;
}
/**
* \@description
* Returns a multicasting observable of value changes for the control that emits every time the
* value of the control changes in the UI or programmatically.
* If the control is not present, null is returned.
* @return {?}
*/
get valueChanges() {
return this.control ? this.control.valueChanges : null;
}
/**
* \@description
* Returns an array that represents the path from the top-level form to this control.
* Each index is the string name of the control on that level.
* @return {?}
*/
get path() { return null; }
/**
* \@description
* Resets the control with the provided value if the control is present.
* @param {?=} value
* @return {?}
*/
reset(value = undefined) {
if (this.control)
this.control.reset(value);
}
/**
* \@description
* Reports whether the control with the given path has the error specified.
*
* \@usageNotes
* For example, for the following `FormGroup`:
*
* ```
* form = new FormGroup({
* address: new FormGroup({ street: new FormControl() })
* });
* ```
*
* The path to the 'street' control from the root form would be 'address' -> 'street'.
*
* It can be provided to this method in one of two formats:
*
* 1. An array of string control names, e.g. `['address', 'street']`
* 1. A period-delimited list of control names in one string, e.g. `'address.street'`
*
* If no path is given, this method checks for the error on the current control.
*
* @param {?} errorCode The code of the error to check
* @param {?=} path A list of control names that designates how to move from the current control
* to the control that should be queried for errors.
*
* @return {?} whether the given error is present in the control at the given path.
*
* If the control is not present, false is returned.
*/
hasError(errorCode, path) {
return this.control ? this.control.hasError(errorCode, path) : false;
}
/**
* \@description
* Reports error data for the control with the given path.
*
* \@usageNotes
* For example, for the following `FormGroup`:
*
* ```
* form = new FormGroup({
* address: new FormGroup({ street: new FormControl() })
* });
* ```
*
* The path to the 'street' control from the root form would be 'address' -> 'street'.
*
* It can be provided to this method in one of two formats:
*
* 1. An array of string control names, e.g. `['address', 'street']`
* 1. A period-delimited list of control names in one string, e.g. `'address.street'`
*
* @param {?} errorCode The code of the error to check
* @param {?=} path A list of control names that designates how to move from the current control
* to the control that should be queried for errors.
*
* @return {?} error data for that particular error. If the control or error is not present,
* null is returned.
*/
getError(errorCode, path) {
return this.control ? this.control.getError(errorCode, path) : null;
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* \@description
* A base class for directives that contain multiple registered instances of `NgControl`.
* Only used by the forms module.
*
* \@publicApi
* @abstract
*/
class ControlContainer extends AbstractControlDirective {
/**
* \@description
* The top-level form directive for the control.
* @return {?}
*/
get formDirective() { return null; }
/**
* \@description
* The path to this group.
* @return {?}
*/
get path() { return null; }
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @return {?}
*/
function unimplemented() {
throw new Error('unimplemented');
}
/**
* \@description
* A base class that all control `FormControl`-based directives extend. It binds a `FormControl`
* object to a DOM element.
*
* \@publicApi
* @abstract
*/
class NgControl extends AbstractControlDirective {
constructor() {
super(...arguments);
/**
* \@description
* The parent form for the control.
*
* \@internal
*/
this._parent = null;
/**
* \@description
* The name for the control
*/
this.name = null;
/**
* \@description
* The value accessor for the control
*/
this.valueAccessor = null;
/**
* \@description
* The uncomposed array of synchronous validators for the control
*
* \@internal
*/
this._rawValidators = [];
/**
* \@description
* The uncomposed array of async validators for the control
*
* \@internal
*/
this._rawAsyncValidators = [];
}
/**
* \@description
* The registered synchronous validator function for the control
*
* @throws An exception that this method is not implemented
* @return {?}
*/
get validator() { return (/** @type {?} */ (unimplemented())); }
/**
* \@description
* The registered async validator function for the control
*
* @throws An exception that this method is not implemented
* @return {?}
*/
get asyncValidator() { return (/** @type {?} */ (unimplemented())); }
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class AbstractControlStatus {
/**
* @param {?} cd
*/
constructor(cd) { this._cd = cd; }
/**
* @return {?}
*/
get ngClassUntouched() { return this._cd.control ? this._cd.control.untouched : false; }
/**
* @return {?}
*/
get ngClassTouched() { return this._cd.control ? this._cd.control.touched : false; }
/**
* @return {?}
*/
get ngClassPristine() { return this._cd.control ? this._cd.control.pristine : false; }
/**
* @return {?}
*/
get ngClassDirty() { return this._cd.control ? this._cd.control.dirty : false; }
/**
* @return {?}
*/
get ngClassValid() { return this._cd.control ? this._cd.control.valid : false; }
/**
* @return {?}
*/
get ngClassInvalid() { return this._cd.control ? this._cd.control.invalid : false; }
/**
* @return {?}
*/
get ngClassPending() { return this._cd.control ? this._cd.control.pending : false; }
}
/** @type {?} */
const ngControlStatusHost = {
'[class.ng-untouched]': 'ngClassUntouched',
'[class.ng-touched]': 'ngClassTouched',
'[class.ng-pristine]': 'ngClassPristine',
'[class.ng-dirty]': 'ngClassDirty',
'[class.ng-valid]': 'ngClassValid',
'[class.ng-invalid]': 'ngClassInvalid',
'[class.ng-pending]': 'ngClassPending',
};
/**
* \@description
* Directive automatically applied to Angular form controls that sets CSS classes
* based on control status.
*
* \@usageNotes
*
* ### CSS classes applied
*
* The following classes are applied as the properties become true:
*
* * ng-valid
* * ng-invalid
* * ng-pending
* * ng-pristine
* * ng-dirty
* * ng-untouched
* * ng-touched
*
* \@ngModule ReactiveFormsModule
* \@ngModule FormsModule
* \@publicApi
*/
class NgControlStatus extends AbstractControlStatus {
/**
* @param {?} cd
*/
constructor(cd) { super(cd); }
}
NgControlStatus.decorators = [
{ type: Directive, args: [{ selector: '[formControlName],[ngModel],[formControl]', host: ngControlStatusHost },] }
];
/** @nocollapse */
NgControlStatus.ctorParameters = () => [
{ type: NgControl, decorators: [{ type: Self }] }
];
/**
* \@description
* Directive automatically applied to Angular form groups that sets CSS classes
* based on control status (valid/invalid/dirty/etc).
*
* @see `NgControlStatus`
*
* \@ngModule ReactiveFormsModule
* \@ngModule FormsModule
* \@publicApi
*/
class NgControlStatusGroup extends AbstractControlStatus {
/**
* @param {?} cd
*/
constructor(cd) { super(cd); }
}
NgControlStatusGroup.decorators = [
{ type: Directive, args: [{
selector: '[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]',
host: ngControlStatusHost
},] }
];
/** @nocollapse */
NgControlStatusGroup.ctorParameters = () => [
{ type: ControlContainer, decorators: [{ type: Self }] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} value
* @return {?}
*/
function isEmptyInputValue(value) {
// we don't check for string here so it also works with arrays
return value == null || value.length === 0;
}
/**
* \@description
* An `InjectionToken` for registering additional synchronous validators used with `AbstractControl`s.
*
* @see `NG_ASYNC_VALIDATORS`
*
* \@usageNotes
*
* ### Providing a custom validator
*
* The following example registers a custom validator directive. Adding the validator to the
* existing collection of validators requires the `multi: true` option.
*
* ```typescript
* \@Directive({
* selector: '[customValidator]',
* providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}]
* })
* class CustomValidatorDirective implements Validator {
* validate(control: AbstractControl): ValidationErrors | null {
* return { 'custom': true };
* }
* }
* ```
*
* \@publicApi
* @type {?}
*/
const NG_VALIDATORS = new InjectionToken('NgValidators');
/**
* \@description
* An `InjectionToken` for registering additional asynchronous validators used with `AbstractControl`s.
*
* @see `NG_VALIDATORS`
*
* \@publicApi
* @type {?}
*/
const NG_ASYNC_VALIDATORS = new InjectionToken('NgAsyncValidators');
/** @type {?} */
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])?)*$/;
/**
* \@description
* Provides a set of built-in validators that can be used by form controls.
*
* A validator is a function that processes a `FormControl` or collection of
* controls and returns an error map or null. A null map means that validation has passed.
*
* @see [Form Validation](/guide/form-validation)
*
* \@publicApi
*/
class Validators {
/**
* \@description
* Validator that requires the control's value to be greater than or equal to the provided number.
* The validator exists only as a function and not as a directive.
*
* \@usageNotes
*
* ### Validate against a minimum of 3
*
* ```typescript
* const control = new FormControl(2, Validators.min(3));
*
* console.log(control.errors); // {min: {min: 3, actual: 2}}
* ```
*
* @param {?} min
* @return {?} A validator function that returns an error map with the
* `min` property if the validation check fails, otherwise `null`.
*
*/
static min(min) {
return (/**
* @param {?} control
* @return {?}
*/
(control) => {
if (isEmptyInputValue(control.value) || isEmptyInputValue(min)) {
return null; // don't validate empty values to allow optional controls
}
/** @type {?} */
const value = parseFloat(control.value);
// Controls with NaN values after parsing should be treated as not having a
// minimum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-min
return !isNaN(value) && value < min ? { 'min': { 'min': min, 'actual': control.value } } : null;
});
}
/**
* \@description
* Validator that requires the control's value to be less than or equal to the provided number.
* The validator exists only as a function and not as a directive.
*
* \@usageNotes
*
* ### Validate against a maximum of 15
*
* ```typescript
* const control = new FormControl(16, Validators.max(15));
*
* console.log(control.errors); // {max: {max: 15, actual: 16}}
* ```
*
* @param {?} max
* @return {?} A validator function that returns an error map with the
* `max` property if the validation check fails, otherwise `null`.
*
*/
static max(max) {
return (/**
* @param {?} control
* @return {?}
*/
(control) => {
if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) {
return null; // don't validate empty values to allow optional controls
}
/** @type {?} */
const value = parseFloat(control.value);
// Controls with NaN values after parsing should be treated as not having a
// maximum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-max
return !isNaN(value) && value > max ? { 'max': { 'max': max, 'actual': control.value } } : null;
});
}
/**
* \@description
* Validator that requires the control have a non-empty value.
*
* \@usageNotes
*
* ### Validate that the field is non-empty
*
* ```typescript
* const control = new FormControl('', Validators.required);
*
* console.log(control.errors); // {required: true}
* ```
*
* @param {?} control
* @return {?} An error map with the `required` property
* if the validation check fails, otherwise `null`.
*
*/
static required(control) {
return isEmptyInputValue(control.value) ? { 'required': true } : null;
}
/**
* \@description
* Validator that requires the control's value be true. This validator is commonly
* used for required checkboxes.
*
* \@usageNotes
*
* ### Validate that the field value is true
*
* ```typescript
* const control = new FormControl('', Validators.requiredTrue);
*
* console.log(control.errors); // {required: true}
* ```
*
* @param {?} control
* @return {?} An error map that contains the `required` property
* set to `true` if the validation check fails, otherwise `null`.
*/
static requiredTrue(control) {
return control.value === true ? null : { 'required': true };
}
/**
* \@description
* Validator that requires the control's value pass an email validation test.
*
* \@usageNotes
*
* ### Validate that the field matches a valid email pattern
*
* ```typescript
* const control = new FormControl('bad\@', Validators.email);
*
* console.log(control.errors); // {email: true}
* ```
*
* @param {?} control
* @return {?} An error map with the `email` property
* if the validation check fails, otherwise `null`.
*
*/
static email(control) {
if (isEmptyInputValue(control.value)) {
return null; // don't validate empty values to allow optional controls
}
return EMAIL_REGEXP.test(control.value) ? null : { 'email': true };
}
/**
* \@description
* Validator that requires the length of the control's value to be greater than or equal
* to the provided minimum length. This validator is also provided by default if you use the
* the HTML5 `minlength` attribute.
*
* \@usageNotes
*
* ### Validate that the field has a minimum of 3 characters
*
* ```typescript
* const control = new FormControl('ng', Validators.minLength(3));
*
* console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}}
* ```
*
* ```html
*
* ```
*
* @param {?} minLength
* @return {?} A validator function that returns an error map with the
* `minlength` if the validation check fails, otherwise `null`.
*/
static minLength(minLength) {
return (/**
* @param {?} control
* @return {?}
*/
(control) => {
if (isEmptyInputValue(control.value)) {
return null; // don't validate empty values to allow optional controls
}
/** @type {?} */
const length = control.value ? control.value.length : 0;
return length < minLength ?
{ 'minlength': { 'requiredLength': minLength, 'actualLength': length } } :
null;
});
}
/**
* \@description
* Validator that requires the length of the control's value to be less than or equal
* to the provided maximum length. This validator is also provided by default if you use the
* the HTML5 `maxlength` attribute.
*
* \@usageNotes
*
* ### Validate that the field has maximum of 5 characters
*
* ```typescript
* const control = new FormControl('Angular', Validators.maxLength(5));
*
* console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}}
* ```
*
* ```html
*
* ```
*
* @param {?} maxLength
* @return {?} A validator function that returns an error map with the
* `maxlength` property if the validation check fails, otherwise `null`.
*/
static maxLength(maxLength) {
return (/**
* @param {?} control
* @return {?}
*/
(control) => {
/** @type {?} */
const length = control.value ? control.value.length : 0;
return length > maxLength ?
{ 'maxlength': { 'requiredLength': maxLength, 'actualLength': length } } :
null;
});
}
/**
* \@description
* Validator that requires the control's value to match a regex pattern. This validator is also
* provided by default if you use the HTML5 `pattern` attribute.
*
* Note that if a Regexp is provided, the Regexp is used as is to test the values. On the other
* hand, if a string is passed, the `^` character is prepended and the `$` character is
* appended to the provided string (if not already present), and the resulting regular
* expression is used to test the values.
*
* \@usageNotes
*
* ### Validate that the field only contains letters or spaces
*
* ```typescript
* const control = new FormControl('1', Validators.pattern('[a-zA-Z ]*'));
*
* console.log(control.errors); // {pattern: {requiredPattern: '^[a-zA-Z ]*$', actualValue: '1'}}
* ```
*
* ```html
*
* ```
*
* @param {?} pattern
* @return {?} A validator function that returns an error map with the
* `pattern` property if the validation check fails, otherwise `null`.
*/
static pattern(pattern) {
if (!pattern)
return Validators.nullValidator;
/** @type {?} */
let regex;
/** @type {?} */
let regexStr;
if (typeof pattern === 'string') {
regexStr = '';
if (pattern.charAt(0) !== '^')
regexStr += '^';
regexStr += pattern;
if (pattern.charAt(pattern.length - 1) !== '$')
regexStr += '$';
regex = new RegExp(regexStr);
}
else {
regexStr = pattern.toString();
regex = pattern;
}
return (/**
* @param {?} control
* @return {?}
*/
(control) => {
if (isEmptyInputValue(control.value)) {
return null; // don't validate empty values to allow optional controls
}
/** @type {?} */
const value = control.value;
return regex.test(value) ? null :
{ 'pattern': { 'requiredPattern': regexStr, 'actualValue': value } };
});
}
/**
* \@description
* Validator that performs no operation.
* @param {?} control
* @return {?}
*/
static nullValidator(control) { return null; }
/**
* @param {?} validators
* @return {?}
*/
static compose(validators) {
if (!validators)
return null;
/** @type {?} */
const presentValidators = (/** @type {?} */ (validators.filter(isPresent)));
if (presentValidators.length == 0)
return null;
return (/**
* @param {?} control
* @return {?}
*/
function (control) {
return _mergeErrors(_executeValidators(control, presentValidators));
});
}
/**
* \@description
* Compose multiple async validators into a single function that returns the union
* of the individual error objects for the provided control.
*
* @param {?} validators
* @return {?} A validator function that returns an error map with the
* merged error objects of the async validators if the validation check fails, otherwise `null`.
*/
static composeAsync(validators) {
if (!validators)
return null;
/** @type {?} */
const presentValidators = (/** @type {?} */ (validators.filter(isPresent)));
if (presentValidators.length == 0)
return null;
return (/**
* @param {?} control
* @return {?}
*/
function (control) {
/** @type {?} */
const observables = _executeAsyncValidators(control, presentValidators).map(toObservable);
return forkJoin(observables).pipe(map(_mergeErrors));
});
}
}
/**
* @param {?} o
* @return {?}
*/
function isPresent(o) {
return o != null;
}
/**
* @param {?} r
* @return {?}
*/
function toObservable(r) {
/** @type {?} */
const obs = ɵisPromise(r) ? from(r) : r;
if (!(ɵisObservable(obs))) {
throw new Error(`Expected validator to return Promise or Observable.`);
}
return obs;
}
/**
* @param {?} control
* @param {?} validators
* @return {?}
*/
function _executeValidators(control, validators) {
return validators.map((/**
* @param {?} v
* @return {?}
*/
v => v(control)));
}
/**
* @param {?} control
* @param {?} validators
* @return {?}
*/
function _executeAsyncValidators(control, validators) {
return validators.map((/**
* @param {?} v
* @return {?}
*/
v => v(control)));
}
/**
* @param {?} arrayOfErrors
* @return {?}
*/
function _mergeErrors(arrayOfErrors) {
/** @type {?} */
const res = arrayOfErrors.reduce((/**
* @param {?} res
* @param {?} errors
* @return {?}
*/
(res, errors) => {
return errors != null ? Object.assign({}, (/** @type {?} */ (res)), errors) : (/** @type {?} */ (res));
}), {});
return Object.keys(res).length === 0 ? null : res;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @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
*/
/**
* @param {?} validator
* @return {?}
*/
function normalizeValidator(validator) {
if (((/** @type {?} */ (validator))).validate) {
return (/**
* @param {?} c
* @return {?}
*/
(c) => ((/** @type {?} */ (validator))).validate(c));
}
else {
return (/** @type {?} */ (validator));
}
}
/**
* @param {?} validator
* @return {?}
*/
function normalizeAsyncValidator(validator) {
if (((/** @type {?} */ (validator))).validate) {
return (/**
* @param {?} c
* @return {?}
*/
(c) => ((/** @type {?} */ (validator))).validate(c));
}
else {
return (/** @type {?} */ (validator));
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const NUMBER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => NumberValueAccessor)),
multi: true
};
/**
* \@description
* The `ControlValueAccessor` for writing a number value and listening to number input changes.
* The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
* directives.
*
* \@usageNotes
*
* ### Using a number input with a reactive form.
*
* The following example shows how to use a number input with a reactive form.
*
* ```ts
* const totalCountControl = new FormControl();
* ```
*
* ```
*
* ```
*
* \@ngModule ReactiveFormsModule
* \@ngModule FormsModule
* \@publicApi
*/
class NumberValueAccessor {
/**
* @param {?} _renderer
* @param {?} _elementRef
*/
constructor(_renderer, _elementRef) {
this._renderer = _renderer;
this._elementRef = _elementRef;
/**
* \@description
* The registered callback function called when a change or input event occurs on the input
* element.
*/
this.onChange = (/**
* @param {?} _
* @return {?}
*/
(_) => { });
/**
* \@description
* The registered callback function called when a blur event occurs on the input element.
*/
this.onTouched = (/**
* @return {?}
*/
() => { });
}
/**
* Sets the "value" property on the input element.
*
* @param {?} value The checked value
* @return {?}
*/
writeValue(value) {
// The value needs to be normalized for IE9, otherwise it is set to 'null' when null
/** @type {?} */
const normalizedValue = value == null ? '' : value;
this._renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue);
}
/**
* \@description
* Registers a function called when the control value changes.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnChange(fn) {
this.onChange = (/**
* @param {?} value
* @return {?}
*/
(value) => { fn(value == '' ? null : parseFloat(value)); });
}
/**
* \@description
* Registers a function called when the control is touched.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnTouched(fn) { this.onTouched = fn; }
/**
* Sets the "disabled" property on the input element.
*
* @param {?} isDisabled The disabled value
* @return {?}
*/
setDisabledState(isDisabled) {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}
}
NumberValueAccessor.decorators = [
{ type: Directive, args: [{
selector: 'input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]',
host: {
'(change)': 'onChange($event.target.value)',
'(input)': 'onChange($event.target.value)',
'(blur)': 'onTouched()'
},
providers: [NUMBER_VALUE_ACCESSOR]
},] }
];
/** @nocollapse */
NumberValueAccessor.ctorParameters = () => [
{ type: Renderer2 },
{ type: ElementRef }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const RADIO_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => RadioControlValueAccessor)),
multi: true
};
/**
* \@description
* Class used by Angular to track radio buttons. For internal use only.
*/
class RadioControlRegistry {
constructor() {
this._accessors = [];
}
/**
* \@description
* Adds a control to the internal registry. For internal use only.
* @param {?} control
* @param {?} accessor
* @return {?}
*/
add(control, accessor) {
this._accessors.push([control, accessor]);
}
/**
* \@description
* Removes a control from the internal registry. For internal use only.
* @param {?} accessor
* @return {?}
*/
remove(accessor) {
for (let i = this._accessors.length - 1; i >= 0; --i) {
if (this._accessors[i][1] === accessor) {
this._accessors.splice(i, 1);
return;
}
}
}
/**
* \@description
* Selects a radio button. For internal use only.
* @param {?} accessor
* @return {?}
*/
select(accessor) {
this._accessors.forEach((/**
* @param {?} c
* @return {?}
*/
(c) => {
if (this._isSameGroup(c, accessor) && c[1] !== accessor) {
c[1].fireUncheck(accessor.value);
}
}));
}
/**
* @private
* @param {?} controlPair
* @param {?} accessor
* @return {?}
*/
_isSameGroup(controlPair, accessor) {
if (!controlPair[0].control)
return false;
return controlPair[0]._parent === accessor._control._parent &&
controlPair[1].name === accessor.name;
}
}
RadioControlRegistry.decorators = [
{ type: Injectable }
];
/**
* \@description
* The `ControlValueAccessor` for writing radio control values and listening to radio control
* changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
* `NgModel` directives.
*
* \@usageNotes
*
* ### Using radio buttons with reactive form directives
*
* The follow example shows how to use radio buttons in a reactive form. When using radio buttons in
* a reactive form, radio buttons in the same group should have the same `formControlName`.
* Providing a `name` attribute is optional.
*
* {\@example forms/ts/reactiveRadioButtons/reactive_radio_button_example.ts region='Reactive'}
*
* \@ngModule ReactiveFormsModule
* \@ngModule FormsModule
* \@publicApi
*/
class RadioControlValueAccessor {
/**
* @param {?} _renderer
* @param {?} _elementRef
* @param {?} _registry
* @param {?} _injector
*/
constructor(_renderer, _elementRef, _registry, _injector) {
this._renderer = _renderer;
this._elementRef = _elementRef;
this._registry = _registry;
this._injector = _injector;
/**
* \@description
* The registered callback function called when a change event occurs on the input element.
*/
this.onChange = (/**
* @return {?}
*/
() => { });
/**
* \@description
* The registered callback function called when a blur event occurs on the input element.
*/
this.onTouched = (/**
* @return {?}
*/
() => { });
}
/**
* \@description
* A lifecycle method called when the directive is initialized. For internal use only.
*
* @return {?}
*/
ngOnInit() {
this._control = this._injector.get(NgControl);
this._checkName();
this._registry.add(this._control, this);
}
/**
* \@description
* Lifecycle method called before the directive's instance is destroyed. For internal use only.
*
* @return {?}
*/
ngOnDestroy() { this._registry.remove(this); }
/**
* \@description
* Sets the "checked" property value on the radio input element.
*
* @param {?} value The checked value
* @return {?}
*/
writeValue(value) {
this._state = value === this.value;
this._renderer.setProperty(this._elementRef.nativeElement, 'checked', this._state);
}
/**
* \@description
* Registers a function called when the control value changes.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnChange(fn) {
this._fn = fn;
this.onChange = (/**
* @return {?}
*/
() => {
fn(this.value);
this._registry.select(this);
});
}
/**
* Sets the "value" on the radio input element and unchecks it.
*
* @param {?} value
* @return {?}
*/
fireUncheck(value) { this.writeValue(value); }
/**
* \@description
* Registers a function called when the control is touched.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnTouched(fn) { this.onTouched = fn; }
/**
* Sets the "disabled" property on the input element.
*
* @param {?} isDisabled The disabled value
* @return {?}
*/
setDisabledState(isDisabled) {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}
/**
* @private
* @return {?}
*/
_checkName() {
if (this.name && this.formControlName && this.name !== this.formControlName) {
this._throwNameError();
}
if (!this.name && this.formControlName)
this.name = this.formControlName;
}
/**
* @private
* @return {?}
*/
_throwNameError() {
throw new Error(`
If you define both a name and a formControlName attribute on your radio button, their values
must match. Ex:
`);
}
}
RadioControlValueAccessor.decorators = [
{ type: Directive, args: [{
selector: 'input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]',
host: { '(change)': 'onChange()', '(blur)': 'onTouched()' },
providers: [RADIO_VALUE_ACCESSOR]
},] }
];
/** @nocollapse */
RadioControlValueAccessor.ctorParameters = () => [
{ type: Renderer2 },
{ type: ElementRef },
{ type: RadioControlRegistry },
{ type: Injector }
];
RadioControlValueAccessor.propDecorators = {
name: [{ type: Input }],
formControlName: [{ type: Input }],
value: [{ type: Input }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const RANGE_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => RangeValueAccessor)),
multi: true
};
/**
* \@description
* The `ControlValueAccessor` for writing a range value and listening to range input changes.
* The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
* directives.
*
* \@usageNotes
*
* ### Using a range input with a reactive form
*
* The following example shows how to use a range input with a reactive form.
*
* ```ts
* const ageControl = new FormControl();
* ```
*
* ```
*
* ```
*
* \@ngModule ReactiveFormsModule
* \@ngModule FormsModule
* \@publicApi
*/
class RangeValueAccessor {
/**
* @param {?} _renderer
* @param {?} _elementRef
*/
constructor(_renderer, _elementRef) {
this._renderer = _renderer;
this._elementRef = _elementRef;
/**
* \@description
* The registered callback function called when a change or input event occurs on the input
* element.
*/
this.onChange = (/**
* @param {?} _
* @return {?}
*/
(_) => { });
/**
* \@description
* The registered callback function called when a blur event occurs on the input element.
*/
this.onTouched = (/**
* @return {?}
*/
() => { });
}
/**
* Sets the "value" property on the input element.
*
* @param {?} value The checked value
* @return {?}
*/
writeValue(value) {
this._renderer.setProperty(this._elementRef.nativeElement, 'value', parseFloat(value));
}
/**
* \@description
* Registers a function called when the control value changes.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnChange(fn) {
this.onChange = (/**
* @param {?} value
* @return {?}
*/
(value) => { fn(value == '' ? null : parseFloat(value)); });
}
/**
* \@description
* Registers a function called when the control is touched.
*
* @param {?} fn The callback function
* @return {?}
*/
registerOnTouched(fn) { this.onTouched = fn; }
/**
* Sets the "disabled" property on the range input element.
*
* @param {?} isDisabled The disabled value
* @return {?}
*/
setDisabledState(isDisabled) {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}
}
RangeValueAccessor.decorators = [
{ type: Directive, args: [{
selector: 'input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]',
host: {
'(change)': 'onChange($event.target.value)',
'(input)': 'onChange($event.target.value)',
'(blur)': 'onTouched()'
},
providers: [RANGE_VALUE_ACCESSOR]
},] }
];
/** @nocollapse */
RangeValueAccessor.ctorParameters = () => [
{ type: Renderer2 },
{ type: ElementRef }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @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
*/
/** @type {?} */
const FormErrorExamples = {
formControlName: `
In your class:
this.myGroup = new FormGroup({
firstName: new FormControl()
});`,
formGroupName: `
In your class:
this.myGroup = new FormGroup({
person: new FormGroup({ firstName: new FormControl() })
});`,
formArrayName: `
In your class:
this.cityArray = new FormArray([new FormControl('SF')]);
this.myGroup = new FormGroup({
cities: this.cityArray
});`,
ngModelGroup: `
`,
ngModelWithFormGroup: `
`
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class ReactiveErrors {
/**
* @return {?}
*/
static controlParentException() {
throw new Error(`formControlName must be used with a parent formGroup directive. You'll want to add a formGroup
directive and pass it an existing FormGroup instance (you can create one in your class).
Example:
${FormErrorExamples.formControlName}`);
}
/**
* @return {?}
*/
static ngModelGroupException() {
throw new Error(`formControlName cannot be used with an ngModelGroup parent. It is only compatible with parents
that also have a "form" prefix: formGroupName, formArrayName, or formGroup.
Option 1: Update the parent to be formGroupName (reactive form strategy)
${FormErrorExamples.formGroupName}
Option 2: Use ngModel instead of formControlName (template-driven strategy)
${FormErrorExamples.ngModelGroup}`);
}
/**
* @return {?}
*/
static missingFormException() {
throw new Error(`formGroup expects a FormGroup instance. Please pass one in.
Example:
${FormErrorExamples.formControlName}`);
}
/**
* @return {?}
*/
static groupParentException() {
throw new Error(`formGroupName must be used with a parent formGroup directive. You'll want to add a formGroup
directive and pass it an existing FormGroup instance (you can create one in your class).
Example:
${FormErrorExamples.formGroupName}`);
}
/**
* @return {?}
*/
static arrayParentException() {
throw new Error(`formArrayName must be used with a parent formGroup directive. You'll want to add a formGroup
directive and pass it an existing FormGroup instance (you can create one in your class).
Example:
${FormErrorExamples.formArrayName}`);
}
/**
* @return {?}
*/
static disabledAttrWarning() {
console.warn(`
It looks like you're using the disabled attribute with a reactive form directive. If you set disabled to true
when you set up this control in your component class, the disabled attribute will actually be set in the DOM for
you. We recommend using this approach to avoid 'changed after checked' errors.
Example:
form = new FormGroup({
first: new FormControl({value: 'Nancy', disabled: true}, Validators.required),
last: new FormControl('Drew', Validators.required)
});
`);
}
/**
* @param {?} directiveName
* @return {?}
*/
static ngModelWarning(directiveName) {
console.warn(`
It looks like you're using ngModel on the same form field as ${directiveName}.
Support for using the ngModel input property and ngModelChange event with
reactive form directives has been deprecated in Angular v6 and will be removed
in Angular v7.
For more information on this, see our API docs here:
https://angular.io/api/forms/${directiveName === 'formControl' ? 'FormControlDirective'
: 'FormControlName'}#use-with-ngmodel
`);
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const SELECT_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => SelectControlValueAccessor)),
multi: true
};
/**
* @param {?} id
* @param {?} value
* @return {?}
*/
function _buildValueString(id, value) {
if (id == null)
return `${value}`;
if (value && typeof value === 'object')
value = 'Object';
return `${id}: ${value}`.slice(0, 50);
}
/**
* @param {?} valueString
* @return {?}
*/
function _extractId(valueString) {
return valueString.split(':')[0];
}
/**
* \@description
* The `ControlValueAccessor` for writing select control values and listening to select control
* changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
* `NgModel` directives.
*
* \@usageNotes
*
* ### Using select controls in a reactive form
*
* The following examples show how to use a select control in a reactive form.
*
* {\@example forms/ts/reactiveSelectControl/reactive_select_control_example.ts region='Component'}
*
* ### Using select controls in a template-driven form
*
* To use a select in a template-driven form, simply add an `ngModel` and a `name`
* attribute to the main `