@angular/forms
Version:
Angular - directives and services for creating forms
939 lines • 121 kB
JavaScript
/**
* @license
* Copyright Google LLC 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
*/
import { EventEmitter, ɵRuntimeError as RuntimeError } from '@angular/core';
import { asyncValidatorsDroppedWithOptsWarning, missingControlError, missingControlValueError, noControlsError } from '../directives/reactive_errors';
import { addValidators, composeAsyncValidators, composeValidators, hasValidator, removeValidators, toObservable } from '../validators';
/**
* Reports that a control is valid, meaning that no errors exist in the input value.
*
* @see {@link status}
*/
export const VALID = 'VALID';
/**
* Reports that a control is invalid, meaning that an error exists in the input value.
*
* @see {@link status}
*/
export const INVALID = 'INVALID';
/**
* Reports that a control is pending, meaning that async validation is occurring and
* errors are not yet available for the input value.
*
* @see {@link markAsPending}
* @see {@link status}
*/
export const PENDING = 'PENDING';
/**
* Reports that a control is disabled, meaning that the control is exempt from ancestor
* calculations of validity or value.
*
* @see {@link markAsDisabled}
* @see {@link status}
*/
export const DISABLED = 'DISABLED';
/**
* Gets validators from either an options object or given validators.
*/
export function pickValidators(validatorOrOpts) {
return (isOptionsObj(validatorOrOpts) ? validatorOrOpts.validators : validatorOrOpts) || null;
}
/**
* Creates validator function by combining provided validators.
*/
function coerceToValidator(validator) {
return Array.isArray(validator) ? composeValidators(validator) : validator || null;
}
/**
* Gets async validators from either an options object or given validators.
*/
export function pickAsyncValidators(asyncValidator, validatorOrOpts) {
if (typeof ngDevMode === 'undefined' || ngDevMode) {
if (isOptionsObj(validatorOrOpts) && asyncValidator) {
console.warn(asyncValidatorsDroppedWithOptsWarning);
}
}
return (isOptionsObj(validatorOrOpts) ? validatorOrOpts.asyncValidators : asyncValidator) || null;
}
/**
* Creates async validator function by combining provided async validators.
*/
function coerceToAsyncValidator(asyncValidator) {
return Array.isArray(asyncValidator) ? composeAsyncValidators(asyncValidator) :
asyncValidator || null;
}
export function isOptionsObj(validatorOrOpts) {
return validatorOrOpts != null && !Array.isArray(validatorOrOpts) &&
typeof validatorOrOpts === 'object';
}
export function assertControlPresent(parent, isGroup, key) {
const controls = parent.controls;
const collection = isGroup ? Object.keys(controls) : controls;
if (!collection.length) {
throw new RuntimeError(1000 /* RuntimeErrorCode.NO_CONTROLS */, (typeof ngDevMode === 'undefined' || ngDevMode) ? noControlsError(isGroup) : '');
}
if (!controls[key]) {
throw new RuntimeError(1001 /* RuntimeErrorCode.MISSING_CONTROL */, (typeof ngDevMode === 'undefined' || ngDevMode) ? missingControlError(isGroup, key) : '');
}
}
export function assertAllValuesPresent(control, isGroup, value) {
control._forEachChild((_, key) => {
if (value[key] === undefined) {
throw new RuntimeError(1002 /* RuntimeErrorCode.MISSING_CONTROL_VALUE */, (typeof ngDevMode === 'undefined' || ngDevMode) ? missingControlValueError(isGroup, key) :
'');
}
});
}
// clang-format on
/**
* This is the base class for `FormControl`, `FormGroup`, and `FormArray`.
*
* It provides some of the shared behavior that all controls and groups of controls have, like
* running validators, calculating status, and resetting state. It also defines the properties
* that are shared between all sub-classes, like `value`, `valid`, and `dirty`. It shouldn't be
* instantiated directly.
*
* The first type parameter TValue represents the value type of the control (`control.value`).
* The optional type parameter TRawValue represents the raw value type (`control.getRawValue()`).
*
* @see [Forms Guide](/guide/forms)
* @see [Reactive Forms Guide](/guide/reactive-forms)
* @see [Dynamic Forms Guide](/guide/dynamic-form)
*
* @publicApi
*/
export class AbstractControl {
/**
* Initialize the AbstractControl instance.
*
* @param validators The function or array of functions that is used to determine the validity of
* this control synchronously.
* @param asyncValidators The function or array of functions that is used to determine validity of
* this control asynchronously.
*/
constructor(validators, asyncValidators) {
/** @internal */
this._pendingDirty = false;
/**
* Indicates that a control has its own pending asynchronous validation in progress.
*
* @internal
*/
this._hasOwnPendingAsyncValidator = false;
/** @internal */
this._pendingTouched = false;
/** @internal */
this._onCollectionChange = () => { };
this._parent = null;
/**
* A control is `pristine` if the user has not yet changed
* the value in the UI.
*
* @returns True if the user has not yet changed the value in the UI; compare `dirty`.
* Programmatic changes to a control's value do not mark it dirty.
*/
this.pristine = true;
/**
* True if the control is marked as `touched`.
*
* A control is marked `touched` once the user has triggered
* a `blur` event on it.
*/
this.touched = false;
/** @internal */
this._onDisabledChange = [];
this._assignValidators(validators);
this._assignAsyncValidators(asyncValidators);
}
/**
* Returns the function that is used to determine the validity of this control synchronously.
* If multiple validators have been added, this will be a single composed function.
* See `Validators.compose()` for additional information.
*/
get validator() {
return this._composedValidatorFn;
}
set validator(validatorFn) {
this._rawValidators = this._composedValidatorFn = validatorFn;
}
/**
* Returns the function that is used to determine the validity of this control asynchronously.
* If multiple validators have been added, this will be a single composed function.
* See `Validators.compose()` for additional information.
*/
get asyncValidator() {
return this._composedAsyncValidatorFn;
}
set asyncValidator(asyncValidatorFn) {
this._rawAsyncValidators = this._composedAsyncValidatorFn = asyncValidatorFn;
}
/**
* The parent control.
*/
get parent() {
return this._parent;
}
/**
* A control is `valid` when its `status` is `VALID`.
*
* @see {@link AbstractControl.status}
*
* @returns True if the control has passed all of its validation tests,
* false otherwise.
*/
get valid() {
return this.status === VALID;
}
/**
* A control is `invalid` when its `status` is `INVALID`.
*
* @see {@link AbstractControl.status}
*
* @returns True if this control has failed one or more of its validation checks,
* false otherwise.
*/
get invalid() {
return this.status === INVALID;
}
/**
* A control is `pending` when its `status` is `PENDING`.
*
* @see {@link AbstractControl.status}
*
* @returns True if this control is in the process of conducting a validation check,
* false otherwise.
*/
get pending() {
return this.status == PENDING;
}
/**
* A control is `disabled` when its `status` is `DISABLED`.
*
* Disabled controls are exempt from validation checks and
* are not included in the aggregate value of their ancestor
* controls.
*
* @see {@link AbstractControl.status}
*
* @returns True if the control is disabled, false otherwise.
*/
get disabled() {
return this.status === DISABLED;
}
/**
* A control is `enabled` as long as its `status` is not `DISABLED`.
*
* @returns True if the control has any status other than 'DISABLED',
* false if the status is 'DISABLED'.
*
* @see {@link AbstractControl.status}
*
*/
get enabled() {
return this.status !== DISABLED;
}
/**
* A control is `dirty` if the user has changed the value
* in the UI.
*
* @returns True if the user has changed the value of this control in the UI; compare `pristine`.
* Programmatic changes to a control's value do not mark it dirty.
*/
get dirty() {
return !this.pristine;
}
/**
* True if the control has not been marked as touched
*
* A control is `untouched` if the user has not yet triggered
* a `blur` event on it.
*/
get untouched() {
return !this.touched;
}
/**
* Reports the update strategy of the `AbstractControl` (meaning
* the event on which the control updates itself).
* Possible values: `'change'` | `'blur'` | `'submit'`
* Default value: `'change'`
*/
get updateOn() {
return this._updateOn ? this._updateOn : (this.parent ? this.parent.updateOn : 'change');
}
/**
* Sets the synchronous validators that are active on this control. Calling
* this overwrites any existing synchronous validators.
*
* When you add or remove a validator at run time, you must call
* `updateValueAndValidity()` for the new validation to take effect.
*
* If you want to add a new validator without affecting existing ones, consider
* using `addValidators()` method instead.
*/
setValidators(validators) {
this._assignValidators(validators);
}
/**
* Sets the asynchronous validators that are active on this control. Calling this
* overwrites any existing asynchronous validators.
*
* When you add or remove a validator at run time, you must call
* `updateValueAndValidity()` for the new validation to take effect.
*
* If you want to add a new validator without affecting existing ones, consider
* using `addAsyncValidators()` method instead.
*/
setAsyncValidators(validators) {
this._assignAsyncValidators(validators);
}
/**
* Add a synchronous validator or validators to this control, without affecting other validators.
*
* When you add or remove a validator at run time, you must call
* `updateValueAndValidity()` for the new validation to take effect.
*
* Adding a validator that already exists will have no effect. If duplicate validator functions
* are present in the `validators` array, only the first instance would be added to a form
* control.
*
* @param validators The new validator function or functions to add to this control.
*/
addValidators(validators) {
this.setValidators(addValidators(validators, this._rawValidators));
}
/**
* Add an asynchronous validator or validators to this control, without affecting other
* validators.
*
* When you add or remove a validator at run time, you must call
* `updateValueAndValidity()` for the new validation to take effect.
*
* Adding a validator that already exists will have no effect.
*
* @param validators The new asynchronous validator function or functions to add to this control.
*/
addAsyncValidators(validators) {
this.setAsyncValidators(addValidators(validators, this._rawAsyncValidators));
}
/**
* Remove a synchronous validator from this control, without affecting other validators.
* Validators are compared by function reference; you must pass a reference to the exact same
* validator function as the one that was originally set. If a provided validator is not found,
* it is ignored.
*
* @usageNotes
*
* ### Reference to a ValidatorFn
*
* ```
* // Reference to the RequiredValidator
* const ctrl = new FormControl<string | null>('', Validators.required);
* ctrl.removeValidators(Validators.required);
*
* // Reference to anonymous function inside MinValidator
* const minValidator = Validators.min(3);
* const ctrl = new FormControl<string | null>('', minValidator);
* expect(ctrl.hasValidator(minValidator)).toEqual(true)
* expect(ctrl.hasValidator(Validators.min(3))).toEqual(false)
*
* ctrl.removeValidators(minValidator);
* ```
*
* When you add or remove a validator at run time, you must call
* `updateValueAndValidity()` for the new validation to take effect.
*
* @param validators The validator or validators to remove.
*/
removeValidators(validators) {
this.setValidators(removeValidators(validators, this._rawValidators));
}
/**
* Remove an asynchronous validator from this control, without affecting other validators.
* Validators are compared by function reference; you must pass a reference to the exact same
* validator function as the one that was originally set. If a provided validator is not found, it
* is ignored.
*
* When you add or remove a validator at run time, you must call
* `updateValueAndValidity()` for the new validation to take effect.
*
* @param validators The asynchronous validator or validators to remove.
*/
removeAsyncValidators(validators) {
this.setAsyncValidators(removeValidators(validators, this._rawAsyncValidators));
}
/**
* Check whether a synchronous validator function is present on this control. The provided
* validator must be a reference to the exact same function that was provided.
*
* @usageNotes
*
* ### Reference to a ValidatorFn
*
* ```
* // Reference to the RequiredValidator
* const ctrl = new FormControl<number | null>(0, Validators.required);
* expect(ctrl.hasValidator(Validators.required)).toEqual(true)
*
* // Reference to anonymous function inside MinValidator
* const minValidator = Validators.min(3);
* const ctrl = new FormControl<number | null>(0, minValidator);
* expect(ctrl.hasValidator(minValidator)).toEqual(true)
* expect(ctrl.hasValidator(Validators.min(3))).toEqual(false)
* ```
*
* @param validator The validator to check for presence. Compared by function reference.
* @returns Whether the provided validator was found on this control.
*/
hasValidator(validator) {
return hasValidator(this._rawValidators, validator);
}
/**
* Check whether an asynchronous validator function is present on this control. The provided
* validator must be a reference to the exact same function that was provided.
*
* @param validator The asynchronous validator to check for presence. Compared by function
* reference.
* @returns Whether the provided asynchronous validator was found on this control.
*/
hasAsyncValidator(validator) {
return hasValidator(this._rawAsyncValidators, validator);
}
/**
* Empties out the synchronous validator list.
*
* When you add or remove a validator at run time, you must call
* `updateValueAndValidity()` for the new validation to take effect.
*
*/
clearValidators() {
this.validator = null;
}
/**
* Empties out the async validator list.
*
* When you add or remove a validator at run time, you must call
* `updateValueAndValidity()` for the new validation to take effect.
*
*/
clearAsyncValidators() {
this.asyncValidator = null;
}
/**
* Marks the control as `touched`. A control is touched by focus and
* blur events that do not change the value.
*
* @see {@link markAsUntouched()}
* @see {@link markAsDirty()}
* @see {@link markAsPristine()}
*
* @param opts Configuration options that determine how the control propagates changes
* and emits events after marking is applied.
* * `onlySelf`: When true, mark only this control. When false or not supplied,
* marks all direct ancestors. Default is false.
*/
markAsTouched(opts = {}) {
this.touched = true;
if (this._parent && !opts.onlySelf) {
this._parent.markAsTouched(opts);
}
}
/**
* Marks the control and all its descendant controls as `touched`.
* @see {@link markAsTouched()}
*/
markAllAsTouched() {
this.markAsTouched({ onlySelf: true });
this._forEachChild((control) => control.markAllAsTouched());
}
/**
* Marks the control as `untouched`.
*
* If the control has any children, also marks all children as `untouched`
* and recalculates the `touched` status of all parent controls.
*
* @see {@link markAsTouched()}
* @see {@link markAsDirty()}
* @see {@link markAsPristine()}
*
* @param opts Configuration options that determine how the control propagates changes
* and emits events after the marking is applied.
* * `onlySelf`: When true, mark only this control. When false or not supplied,
* marks all direct ancestors. Default is false.
*/
markAsUntouched(opts = {}) {
this.touched = false;
this._pendingTouched = false;
this._forEachChild((control) => {
control.markAsUntouched({ onlySelf: true });
});
if (this._parent && !opts.onlySelf) {
this._parent._updateTouched(opts);
}
}
/**
* Marks the control as `dirty`. A control becomes dirty when
* the control's value is changed through the UI; compare `markAsTouched`.
*
* @see {@link markAsTouched()}
* @see {@link markAsUntouched()}
* @see {@link markAsPristine()}
*
* @param opts Configuration options that determine how the control propagates changes
* and emits events after marking is applied.
* * `onlySelf`: When true, mark only this control. When false or not supplied,
* marks all direct ancestors. Default is false.
*/
markAsDirty(opts = {}) {
this.pristine = false;
if (this._parent && !opts.onlySelf) {
this._parent.markAsDirty(opts);
}
}
/**
* Marks the control as `pristine`.
*
* If the control has any children, marks all children as `pristine`,
* and recalculates the `pristine` status of all parent
* controls.
*
* @see {@link markAsTouched()}
* @see {@link markAsUntouched()}
* @see {@link markAsDirty()}
*
* @param opts Configuration options that determine how the control emits events after
* marking is applied.
* * `onlySelf`: When true, mark only this control. When false or not supplied,
* marks all direct ancestors. Default is false.
*/
markAsPristine(opts = {}) {
this.pristine = true;
this._pendingDirty = false;
this._forEachChild((control) => {
control.markAsPristine({ onlySelf: true });
});
if (this._parent && !opts.onlySelf) {
this._parent._updatePristine(opts);
}
}
/**
* Marks the control as `pending`.
*
* A control is pending while the control performs async validation.
*
* @see {@link AbstractControl.status}
*
* @param opts Configuration options that determine how the control propagates changes and
* emits events after marking is applied.
* * `onlySelf`: When true, mark only this control. When false or not supplied,
* marks all direct ancestors. Default is false.
* * `emitEvent`: When true or not supplied (the default), the `statusChanges`
* observable emits an event with the latest status the control is marked pending.
* When false, no events are emitted.
*
*/
markAsPending(opts = {}) {
this.status = PENDING;
if (opts.emitEvent !== false) {
this.statusChanges.emit(this.status);
}
if (this._parent && !opts.onlySelf) {
this._parent.markAsPending(opts);
}
}
/**
* Disables the control. This means the control is exempt from validation checks and
* excluded from the aggregate value of any parent. Its status is `DISABLED`.
*
* If the control has children, all children are also disabled.
*
* @see {@link AbstractControl.status}
*
* @param opts Configuration options that determine how the control propagates
* changes and emits events after the control is disabled.
* * `onlySelf`: When true, mark only this control. When false or not supplied,
* marks all direct ancestors. Default is false.
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
* `valueChanges`
* observables emit events with the latest status and value when the control is disabled.
* When false, no events are emitted.
*/
disable(opts = {}) {
// If parent has been marked artificially dirty we don't want to re-calculate the
// parent's dirtiness based on the children.
const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf);
this.status = DISABLED;
this.errors = null;
this._forEachChild((control) => {
control.disable({ ...opts, onlySelf: true });
});
this._updateValue();
if (opts.emitEvent !== false) {
this.valueChanges.emit(this.value);
this.statusChanges.emit(this.status);
}
this._updateAncestors({ ...opts, skipPristineCheck });
this._onDisabledChange.forEach((changeFn) => changeFn(true));
}
/**
* Enables the control. This means the control is included in validation checks and
* the aggregate value of its parent. Its status recalculates based on its value and
* its validators.
*
* By default, if the control has children, all children are enabled.
*
* @see {@link AbstractControl.status}
*
* @param opts Configure options that control how the control propagates changes and
* emits events when marked as untouched
* * `onlySelf`: When true, mark only this control. When false or not supplied,
* marks all direct ancestors. Default is false.
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
* `valueChanges`
* observables emit events with the latest status and value when the control is enabled.
* When false, no events are emitted.
*/
enable(opts = {}) {
// If parent has been marked artificially dirty we don't want to re-calculate the
// parent's dirtiness based on the children.
const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf);
this.status = VALID;
this._forEachChild((control) => {
control.enable({ ...opts, onlySelf: true });
});
this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
this._updateAncestors({ ...opts, skipPristineCheck });
this._onDisabledChange.forEach((changeFn) => changeFn(false));
}
_updateAncestors(opts) {
if (this._parent && !opts.onlySelf) {
this._parent.updateValueAndValidity(opts);
if (!opts.skipPristineCheck) {
this._parent._updatePristine();
}
this._parent._updateTouched();
}
}
/**
* Sets the parent of the control
*
* @param parent The new parent.
*/
setParent(parent) {
this._parent = parent;
}
/**
* The raw value of this control. For most control implementations, the raw value will include
* disabled children.
*/
getRawValue() {
return this.value;
}
/**
* Recalculates the value and validation status of the control.
*
* By default, it also updates the value and validity of its ancestors.
*
* @param opts Configuration options determine how the control propagates changes and emits events
* after updates and validity checks are applied.
* * `onlySelf`: When true, only update this control. When false or not supplied,
* update all direct ancestors. Default is false.
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
* `valueChanges`
* observables emit events with the latest status and value when the control is updated.
* When false, no events are emitted.
*/
updateValueAndValidity(opts = {}) {
this._setInitialStatus();
this._updateValue();
if (this.enabled) {
this._cancelExistingSubscription();
this.errors = this._runValidator();
this.status = this._calculateStatus();
if (this.status === VALID || this.status === PENDING) {
this._runAsyncValidator(opts.emitEvent);
}
}
if (opts.emitEvent !== false) {
this.valueChanges.emit(this.value);
this.statusChanges.emit(this.status);
}
if (this._parent && !opts.onlySelf) {
this._parent.updateValueAndValidity(opts);
}
}
/** @internal */
_updateTreeValidity(opts = { emitEvent: true }) {
this._forEachChild((ctrl) => ctrl._updateTreeValidity(opts));
this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
}
_setInitialStatus() {
this.status = this._allControlsDisabled() ? DISABLED : VALID;
}
_runValidator() {
return this.validator ? this.validator(this) : null;
}
_runAsyncValidator(emitEvent) {
if (this.asyncValidator) {
this.status = PENDING;
this._hasOwnPendingAsyncValidator = true;
const obs = toObservable(this.asyncValidator(this));
this._asyncValidationSubscription = obs.subscribe((errors) => {
this._hasOwnPendingAsyncValidator = false;
// This will trigger the recalculation of the validation status, which depends on
// the state of the asynchronous validation (whether it is in progress or not). So, it is
// necessary that we have updated the `_hasOwnPendingAsyncValidator` boolean flag first.
this.setErrors(errors, { emitEvent });
});
}
}
_cancelExistingSubscription() {
if (this._asyncValidationSubscription) {
this._asyncValidationSubscription.unsubscribe();
this._hasOwnPendingAsyncValidator = false;
}
}
/**
* Sets errors on a form control when running validations manually, rather than automatically.
*
* Calling `setErrors` also updates the validity of the parent control.
*
* @param opts Configuration options that determine how the control propagates
* changes and emits events after the control errors are set.
* * `emitEvent`: When true or not supplied (the default), the `statusChanges`
* observable emits an event after the errors are set.
*
* @usageNotes
*
* ### Manually set the errors for a control
*
* ```
* const login = new FormControl('someLogin');
* login.setErrors({
* notUnique: true
* });
*
* expect(login.valid).toEqual(false);
* expect(login.errors).toEqual({ notUnique: true });
*
* login.setValue('someOtherLogin');
*
* expect(login.valid).toEqual(true);
* ```
*/
setErrors(errors, opts = {}) {
this.errors = errors;
this._updateControlsErrors(opts.emitEvent !== false);
}
/**
* Retrieves a child control given the control's name or path.
*
* @param path A dot-delimited string or array of string/number values that define the path to the
* control. If a string is provided, passing it as a string literal will result in improved type
* information. Likewise, if an array is provided, passing it `as const` will cause improved type
* information to be available.
*
* @usageNotes
* ### Retrieve a nested control
*
* For example, to get a `name` control nested within a `person` sub-group:
*
* * `this.form.get('person.name');`
*
* -OR-
*
* * `this.form.get(['person', 'name'] as const);` // `as const` gives improved typings
*
* ### Retrieve a control in a FormArray
*
* When accessing an element inside a FormArray, you can use an element index.
* For example, to get a `price` control from the first element in an `items` array you can use:
*
* * `this.form.get('items.0.price');`
*
* -OR-
*
* * `this.form.get(['items', 0, 'price']);`
*/
get(path) {
let currPath = path;
if (currPath == null)
return null;
if (!Array.isArray(currPath))
currPath = currPath.split('.');
if (currPath.length === 0)
return null;
return currPath.reduce((control, name) => control && control._find(name), this);
}
/**
* @description
* Reports error data for the control with the given path.
*
* @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.
*
* @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'`
*
* @returns error data for that particular error. If the control or error is not present,
* null is returned.
*/
getError(errorCode, path) {
const control = path ? this.get(path) : this;
return control && control.errors ? control.errors[errorCode] : null;
}
/**
* @description
* Reports whether the control with the given path has the error specified.
*
* @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.
*
* @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.
*
* @returns 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.getError(errorCode, path);
}
/**
* Retrieves the top-level ancestor of this control.
*/
get root() {
let x = this;
while (x._parent) {
x = x._parent;
}
return x;
}
/** @internal */
_updateControlsErrors(emitEvent) {
this.status = this._calculateStatus();
if (emitEvent) {
this.statusChanges.emit(this.status);
}
if (this._parent) {
this._parent._updateControlsErrors(emitEvent);
}
}
/** @internal */
_initObservables() {
this.valueChanges = new EventEmitter();
this.statusChanges = new EventEmitter();
}
_calculateStatus() {
if (this._allControlsDisabled())
return DISABLED;
if (this.errors)
return INVALID;
if (this._hasOwnPendingAsyncValidator || this._anyControlsHaveStatus(PENDING))
return PENDING;
if (this._anyControlsHaveStatus(INVALID))
return INVALID;
return VALID;
}
/** @internal */
_anyControlsHaveStatus(status) {
return this._anyControls((control) => control.status === status);
}
/** @internal */
_anyControlsDirty() {
return this._anyControls((control) => control.dirty);
}
/** @internal */
_anyControlsTouched() {
return this._anyControls((control) => control.touched);
}
/** @internal */
_updatePristine(opts = {}) {
this.pristine = !this._anyControlsDirty();
if (this._parent && !opts.onlySelf) {
this._parent._updatePristine(opts);
}
}
/** @internal */
_updateTouched(opts = {}) {
this.touched = this._anyControlsTouched();
if (this._parent && !opts.onlySelf) {
this._parent._updateTouched(opts);
}
}
/** @internal */
_registerOnCollectionChange(fn) {
this._onCollectionChange = fn;
}
/** @internal */
_setUpdateStrategy(opts) {
if (isOptionsObj(opts) && opts.updateOn != null) {
this._updateOn = opts.updateOn;
}
}
/**
* Check to see if parent has been marked artificially dirty.
*
* @internal
*/
_parentMarkedDirty(onlySelf) {
const parentDirty = this._parent && this._parent.dirty;
return !onlySelf && !!parentDirty && !this._parent._anyControlsDirty();
}
/** @internal */
_find(name) {
return null;
}
/**
* Internal implementation of the `setValidators` method. Needs to be separated out into a
* different method, because it is called in the constructor and it can break cases where
* a control is extended.
*/
_assignValidators(validators) {
this._rawValidators = Array.isArray(validators) ? validators.slice() : validators;
this._composedValidatorFn = coerceToValidator(this._rawValidators);
}
/**
* Internal implementation of the `setAsyncValidators` method. Needs to be separated out into a
* different method, because it is called in the constructor and it can break cases where
* a control is extended.
*/
_assignAsyncValidators(validators) {
this._rawAsyncValidators = Array.isArray(validators) ? validators.slice() : validators;
this._composedAsyncValidatorFn = coerceToAsyncValidator(this._rawAsyncValidators);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJzdHJhY3RfbW9kZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9mb3Jtcy9zcmMvbW9kZWwvYWJzdHJhY3RfbW9kZWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUFDLFlBQVksRUFBRSxhQUFhLElBQUksWUFBWSxFQUF3QixNQUFNLGVBQWUsQ0FBQztBQUdqRyxPQUFPLEVBQUMscUNBQXFDLEVBQUUsbUJBQW1CLEVBQUUsd0JBQXdCLEVBQUUsZUFBZSxFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFJcEosT0FBTyxFQUFDLGFBQWEsRUFBRSxzQkFBc0IsRUFBRSxpQkFBaUIsRUFBRSxZQUFZLEVBQUUsZ0JBQWdCLEVBQUUsWUFBWSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBR3JJOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDO0FBRTdCOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDO0FBRWpDOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBRyxTQUFTLENBQUM7QUFFakM7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUFHLFVBQVUsQ0FBQztBQW1CbkM7O0dBRUc7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUFDLGVBQ0k7SUFDakMsT0FBTyxDQUFDLFlBQVksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsZUFBZSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsZUFBZSxDQUFDLElBQUksSUFBSSxDQUFDO0FBQ2hHLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsaUJBQWlCLENBQUMsU0FBeUM7SUFDbEUsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxTQUFT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