docs(forms): add docs for AbstractControl
This commit is contained in:
parent
00a24b63da
commit
21516c32e6
|
@ -76,6 +76,14 @@ function coerceToAsyncValidator(asyncValidator: AsyncValidatorFn | AsyncValidato
|
|||
}
|
||||
|
||||
/**
|
||||
* @whatItDoes This is the base class for {@link FormControl}, {@link FormGroup}, and
|
||||
* {@link 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.
|
||||
*
|
||||
* @stable
|
||||
*/
|
||||
export abstract class AbstractControl {
|
||||
|
@ -95,49 +103,146 @@ export abstract class AbstractControl {
|
|||
|
||||
constructor(public validator: ValidatorFn, public asyncValidator: AsyncValidatorFn) {}
|
||||
|
||||
/**
|
||||
* The value of the control.
|
||||
*/
|
||||
get value(): any { return this._value; }
|
||||
|
||||
/**
|
||||
* The validation status of the control. There are four possible
|
||||
* validation statuses:
|
||||
*
|
||||
* * **VALID**: control has passed all validation checks
|
||||
* * **INVALID**: control has failed at least one validation check
|
||||
* * **PENDING**: control is in the midst of conducting a validation check
|
||||
* * **DISABLED**: control is exempt from validation checks
|
||||
*
|
||||
* These statuses are mutually exclusive, so a control cannot be
|
||||
* both valid AND invalid or invalid AND disabled.
|
||||
*/
|
||||
get status(): string { return this._status; }
|
||||
|
||||
/**
|
||||
* A control is `valid` when its `status === VALID`.
|
||||
*
|
||||
* In order to have this status, the control must have passed all its
|
||||
* validation checks.
|
||||
*/
|
||||
get valid(): boolean { return this._status === VALID; }
|
||||
|
||||
/**
|
||||
* A control is `invalid` when its `status === INVALID`.
|
||||
*
|
||||
* In order to have this status, the control must have failed
|
||||
* at least one of its validation checks.
|
||||
*/
|
||||
get invalid(): boolean { return this._status === INVALID; }
|
||||
|
||||
/**
|
||||
* Returns the errors of this control.
|
||||
* A control is `pending` when its `status === PENDING`.
|
||||
*
|
||||
* In order to have this status, the control must be in the
|
||||
* middle of conducting a validation check.
|
||||
*/
|
||||
get pending(): boolean { return this._status == PENDING; }
|
||||
|
||||
/**
|
||||
* A control is `disabled` when its `status === DISABLED`.
|
||||
*
|
||||
* Disabled controls are exempt from validation checks and
|
||||
* are not included in the aggregate value of their ancestor
|
||||
* controls.
|
||||
*/
|
||||
get disabled(): boolean { return this._status === DISABLED; }
|
||||
|
||||
/**
|
||||
* A control is `enabled` as long as its `status !== DISABLED`.
|
||||
*
|
||||
* In other words, it has a status of `VALID`, `INVALID`, or
|
||||
* `PENDING`.
|
||||
*/
|
||||
get enabled(): boolean { return this._status !== DISABLED; }
|
||||
|
||||
/**
|
||||
* Returns any errors generated by failing validation. If there
|
||||
* are no errors, it will return null.
|
||||
*/
|
||||
get errors(): {[key: string]: any} { return this._errors; }
|
||||
|
||||
/**
|
||||
* A control is `pristine` if the user has not yet changed
|
||||
* the value in the UI.
|
||||
*
|
||||
* Note that programmatic changes to a control's value will
|
||||
* *not* mark it dirty.
|
||||
*/
|
||||
get pristine(): boolean { return this._pristine; }
|
||||
|
||||
/**
|
||||
* A control is `dirty` if the user has changed the value
|
||||
* in the UI.
|
||||
*
|
||||
* Note that programmatic changes to a control's value will
|
||||
* *not* mark it dirty.
|
||||
*/
|
||||
get dirty(): boolean { return !this.pristine; }
|
||||
|
||||
/**
|
||||
* A control is marked `touched` once the user has triggered
|
||||
* a `blur` event on it.
|
||||
*/
|
||||
get touched(): boolean { return this._touched; }
|
||||
|
||||
/**
|
||||
* A control is `untouched` if the user has not yet triggered
|
||||
* a `blur` event on it.
|
||||
*/
|
||||
get untouched(): boolean { return !this._touched; }
|
||||
|
||||
/**
|
||||
* Emits an event every time the value of the control changes, in
|
||||
* the UI or programmatically.
|
||||
*/
|
||||
get valueChanges(): Observable<any> { return this._valueChanges; }
|
||||
|
||||
/**
|
||||
* Emits an event every time the validation status of the control
|
||||
* is re-calculated.
|
||||
*/
|
||||
get statusChanges(): Observable<any> { return this._statusChanges; }
|
||||
|
||||
get pending(): boolean { return this._status == PENDING; }
|
||||
|
||||
get disabled(): boolean { return this._status === DISABLED; }
|
||||
|
||||
get enabled(): boolean { return this._status !== DISABLED; }
|
||||
|
||||
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]): void {
|
||||
this.asyncValidator = coerceToAsyncValidator(newValidator);
|
||||
}
|
||||
|
||||
clearAsyncValidators(): void { this.asyncValidator = null; }
|
||||
|
||||
/**
|
||||
* Sets the synchronous validators that are active on this control. Calling
|
||||
* this will overwrite any existing sync validators.
|
||||
*/
|
||||
setValidators(newValidator: ValidatorFn|ValidatorFn[]): void {
|
||||
this.validator = coerceToValidator(newValidator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the async validators that are active on this control. Calling this
|
||||
* will overwrite any existing async validators.
|
||||
*/
|
||||
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]): void {
|
||||
this.asyncValidator = coerceToAsyncValidator(newValidator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empties out the sync validator list.
|
||||
*/
|
||||
clearValidators(): void { this.validator = null; }
|
||||
|
||||
/**
|
||||
* Empties out the async validator list.
|
||||
*/
|
||||
clearAsyncValidators(): void { this.asyncValidator = null; }
|
||||
|
||||
/**
|
||||
* Marks the control as `touched`.
|
||||
*
|
||||
* This will also mark all direct ancestors as `touched` to maintain
|
||||
* the model.
|
||||
*/
|
||||
markAsTouched({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||
onlySelf = normalizeBool(onlySelf);
|
||||
this._touched = true;
|
||||
|
@ -147,25 +252,13 @@ export abstract class AbstractControl {
|
|||
}
|
||||
}
|
||||
|
||||
markAsDirty({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||
onlySelf = normalizeBool(onlySelf);
|
||||
this._pristine = false;
|
||||
|
||||
if (isPresent(this._parent) && !onlySelf) {
|
||||
this._parent.markAsDirty({onlySelf: onlySelf});
|
||||
}
|
||||
}
|
||||
|
||||
markAsPristine({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||
this._pristine = true;
|
||||
|
||||
this._forEachChild((control: AbstractControl) => { control.markAsPristine({onlySelf: true}); });
|
||||
|
||||
if (isPresent(this._parent) && !onlySelf) {
|
||||
this._parent._updatePristine({onlySelf: onlySelf});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the control as `untouched`.
|
||||
*
|
||||
* If the control has any children, it will also mark all children as `untouched`
|
||||
* to maintain the model, and re-calculate the `touched` status of all parent
|
||||
* controls.
|
||||
*/
|
||||
markAsUntouched({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||
this._touched = false;
|
||||
|
||||
|
@ -177,6 +270,41 @@ export abstract class AbstractControl {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the control as `dirty`.
|
||||
*
|
||||
* This will also mark all direct ancestors as `dirty` to maintain
|
||||
* the model.
|
||||
*/
|
||||
markAsDirty({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||
onlySelf = normalizeBool(onlySelf);
|
||||
this._pristine = false;
|
||||
|
||||
if (isPresent(this._parent) && !onlySelf) {
|
||||
this._parent.markAsDirty({onlySelf: onlySelf});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the control as `pristine`.
|
||||
*
|
||||
* If the control has any children, it will also mark all children as `pristine`
|
||||
* to maintain the model, and re-calculate the `pristine` status of all parent
|
||||
* controls.
|
||||
*/
|
||||
markAsPristine({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||
this._pristine = true;
|
||||
|
||||
this._forEachChild((control: AbstractControl) => { control.markAsPristine({onlySelf: true}); });
|
||||
|
||||
if (isPresent(this._parent) && !onlySelf) {
|
||||
this._parent._updatePristine({onlySelf: onlySelf});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the control as `pending`.
|
||||
*/
|
||||
markAsPending({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||
onlySelf = normalizeBool(onlySelf);
|
||||
this._status = PENDING;
|
||||
|
@ -186,6 +314,12 @@ export abstract class AbstractControl {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the control. This means the control will be exempt from validation checks and
|
||||
* excluded from the aggregate value of any parent. Its status is `DISABLED`.
|
||||
*
|
||||
* If the control has children, all children will be disabled to maintain the model.
|
||||
*/
|
||||
disable({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
|
||||
emitEvent = isPresent(emitEvent) ? emitEvent : true;
|
||||
|
||||
|
@ -203,6 +337,13 @@ export abstract class AbstractControl {
|
|||
this._onDisabledChange(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the control. This means the control will be included in validation checks and
|
||||
* the aggregate value of its parent. Its status is re-calculated based on its value and
|
||||
* its validators.
|
||||
*
|
||||
* If the control has children, all children will be enabled.
|
||||
*/
|
||||
enable({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
|
||||
this._status = VALID;
|
||||
this._forEachChild((control: AbstractControl) => { control.enable({onlySelf: true}); });
|
||||
|
@ -222,12 +363,26 @@ export abstract class AbstractControl {
|
|||
|
||||
setParent(parent: FormGroup|FormArray): void { this._parent = parent; }
|
||||
|
||||
/**
|
||||
* Sets the value of the control. Abstract method (implemented in sub-classes).
|
||||
*/
|
||||
abstract setValue(value: any, options?: Object): void;
|
||||
|
||||
/**
|
||||
* Patches the value of the control. Abstract method (implemented in sub-classes).
|
||||
*/
|
||||
abstract patchValue(value: any, options?: Object): void;
|
||||
|
||||
/**
|
||||
* Resets the control. Abstract method (implemented in sub-classes).
|
||||
*/
|
||||
abstract reset(value?: any, options?: Object): void;
|
||||
|
||||
/**
|
||||
* Re-calculates the value and validation status of the control.
|
||||
*
|
||||
* By default, it will also update the value and validity of its ancestors.
|
||||
*/
|
||||
updateValueAndValidity({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}):
|
||||
void {
|
||||
onlySelf = normalizeBool(onlySelf);
|
||||
|
@ -286,14 +441,14 @@ export abstract class AbstractControl {
|
|||
/**
|
||||
* Sets errors on a form control.
|
||||
*
|
||||
* This is used when validations are run not automatically, but manually by the user.
|
||||
* This is used when validations are run manually by the user, rather than automatically.
|
||||
*
|
||||
* Calling `setErrors` will also update the validity of the parent control.
|
||||
*
|
||||
* ## Usage
|
||||
* ### Example
|
||||
*
|
||||
* ```
|
||||
* var login = new FormControl("someLogin");
|
||||
* const login = new FormControl("someLogin");
|
||||
* login.setErrors({
|
||||
* "notUnique": true
|
||||
* });
|
||||
|
@ -301,7 +456,7 @@ export abstract class AbstractControl {
|
|||
* expect(login.valid).toEqual(false);
|
||||
* expect(login.errors).toEqual({"notUnique": true});
|
||||
*
|
||||
* login.updateValue("someOtherLogin");
|
||||
* login.setValue("someOtherLogin");
|
||||
*
|
||||
* expect(login.valid).toEqual(true);
|
||||
* ```
|
||||
|
@ -313,8 +468,27 @@ export abstract class AbstractControl {
|
|||
this._updateControlsErrors(emitEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a child control given the control's name or path.
|
||||
*
|
||||
* Paths can be passed in as an array or a string delimited by a dot.
|
||||
*
|
||||
* To get a control nested within a `person` sub-group:
|
||||
*
|
||||
* * `this.form.get('person.name');`
|
||||
*
|
||||
* -OR-
|
||||
*
|
||||
* * `this.form.get(['person', 'name']);`
|
||||
*/
|
||||
get(path: Array<string|number>|string): AbstractControl { return _find(this, path, '.'); }
|
||||
|
||||
/**
|
||||
* Returns true if the control with the given path has the error specified. Otherwise
|
||||
* returns null or undefined.
|
||||
*
|
||||
* If no path is given, it checks for the error on the present control.
|
||||
*/
|
||||
getError(errorCode: string, path: string[] = null): any {
|
||||
var control = isPresent(path) && !ListWrapper.isEmpty(path) ? this.get(path) : this;
|
||||
if (isPresent(control) && isPresent(control._errors)) {
|
||||
|
@ -324,10 +498,19 @@ export abstract class AbstractControl {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the control with the given path has the error specified. Otherwise
|
||||
* returns false.
|
||||
*
|
||||
* If no path is given, it checks for the error on the present control.
|
||||
*/
|
||||
hasError(errorCode: string, path: string[] = null): boolean {
|
||||
return isPresent(this.getError(errorCode, path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the top-level ancestor of this control.
|
||||
*/
|
||||
get root(): AbstractControl {
|
||||
let x: AbstractControl = this;
|
||||
|
||||
|
|
Loading…
Reference in New Issue