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
|
* @stable
|
||||||
*/
|
*/
|
||||||
export abstract class AbstractControl {
|
export abstract class AbstractControl {
|
||||||
@ -95,49 +103,146 @@ export abstract class AbstractControl {
|
|||||||
|
|
||||||
constructor(public validator: ValidatorFn, public asyncValidator: AsyncValidatorFn) {}
|
constructor(public validator: ValidatorFn, public asyncValidator: AsyncValidatorFn) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value of the control.
|
||||||
|
*/
|
||||||
get value(): any { return this._value; }
|
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; }
|
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; }
|
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; }
|
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; }
|
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; }
|
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; }
|
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; }
|
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; }
|
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; }
|
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 statusChanges(): Observable<any> { return this._statusChanges; }
|
||||||
|
|
||||||
get pending(): boolean { return this._status == PENDING; }
|
/**
|
||||||
|
* Sets the synchronous validators that are active on this control. Calling
|
||||||
get disabled(): boolean { return this._status === DISABLED; }
|
* this will overwrite any existing sync validators.
|
||||||
|
*/
|
||||||
get enabled(): boolean { return this._status !== DISABLED; }
|
|
||||||
|
|
||||||
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]): void {
|
|
||||||
this.asyncValidator = coerceToAsyncValidator(newValidator);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearAsyncValidators(): void { this.asyncValidator = null; }
|
|
||||||
|
|
||||||
setValidators(newValidator: ValidatorFn|ValidatorFn[]): void {
|
setValidators(newValidator: ValidatorFn|ValidatorFn[]): void {
|
||||||
this.validator = coerceToValidator(newValidator);
|
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; }
|
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 {
|
markAsTouched({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||||
onlySelf = normalizeBool(onlySelf);
|
onlySelf = normalizeBool(onlySelf);
|
||||||
this._touched = true;
|
this._touched = true;
|
||||||
@ -147,25 +252,13 @@ export abstract class AbstractControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
markAsDirty({onlySelf}: {onlySelf?: boolean} = {}): void {
|
/**
|
||||||
onlySelf = normalizeBool(onlySelf);
|
* Marks the control as `untouched`.
|
||||||
this._pristine = false;
|
*
|
||||||
|
* If the control has any children, it will also mark all children as `untouched`
|
||||||
if (isPresent(this._parent) && !onlySelf) {
|
* to maintain the model, and re-calculate the `touched` status of all parent
|
||||||
this._parent.markAsDirty({onlySelf: onlySelf});
|
* 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});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
markAsUntouched({onlySelf}: {onlySelf?: boolean} = {}): void {
|
markAsUntouched({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||||
this._touched = false;
|
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 {
|
markAsPending({onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||||
onlySelf = normalizeBool(onlySelf);
|
onlySelf = normalizeBool(onlySelf);
|
||||||
this._status = PENDING;
|
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 {
|
disable({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
|
||||||
emitEvent = isPresent(emitEvent) ? emitEvent : true;
|
emitEvent = isPresent(emitEvent) ? emitEvent : true;
|
||||||
|
|
||||||
@ -203,6 +337,13 @@ export abstract class AbstractControl {
|
|||||||
this._onDisabledChange(true);
|
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 {
|
enable({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
|
||||||
this._status = VALID;
|
this._status = VALID;
|
||||||
this._forEachChild((control: AbstractControl) => { control.enable({onlySelf: true}); });
|
this._forEachChild((control: AbstractControl) => { control.enable({onlySelf: true}); });
|
||||||
@ -222,12 +363,26 @@ export abstract class AbstractControl {
|
|||||||
|
|
||||||
setParent(parent: FormGroup|FormArray): void { this._parent = parent; }
|
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;
|
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;
|
abstract patchValue(value: any, options?: Object): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the control. Abstract method (implemented in sub-classes).
|
||||||
|
*/
|
||||||
abstract reset(value?: any, options?: Object): void;
|
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} = {}):
|
updateValueAndValidity({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}):
|
||||||
void {
|
void {
|
||||||
onlySelf = normalizeBool(onlySelf);
|
onlySelf = normalizeBool(onlySelf);
|
||||||
@ -286,14 +441,14 @@ export abstract class AbstractControl {
|
|||||||
/**
|
/**
|
||||||
* Sets errors on a form control.
|
* 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.
|
* 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({
|
* login.setErrors({
|
||||||
* "notUnique": true
|
* "notUnique": true
|
||||||
* });
|
* });
|
||||||
@ -301,7 +456,7 @@ export abstract class AbstractControl {
|
|||||||
* expect(login.valid).toEqual(false);
|
* expect(login.valid).toEqual(false);
|
||||||
* expect(login.errors).toEqual({"notUnique": true});
|
* expect(login.errors).toEqual({"notUnique": true});
|
||||||
*
|
*
|
||||||
* login.updateValue("someOtherLogin");
|
* login.setValue("someOtherLogin");
|
||||||
*
|
*
|
||||||
* expect(login.valid).toEqual(true);
|
* expect(login.valid).toEqual(true);
|
||||||
* ```
|
* ```
|
||||||
@ -313,8 +468,27 @@ export abstract class AbstractControl {
|
|||||||
this._updateControlsErrors(emitEvent);
|
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, '.'); }
|
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 {
|
getError(errorCode: string, path: string[] = null): any {
|
||||||
var control = isPresent(path) && !ListWrapper.isEmpty(path) ? this.get(path) : this;
|
var control = isPresent(path) && !ListWrapper.isEmpty(path) ? this.get(path) : this;
|
||||||
if (isPresent(control) && isPresent(control._errors)) {
|
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 {
|
hasError(errorCode: string, path: string[] = null): boolean {
|
||||||
return isPresent(this.getError(errorCode, path));
|
return isPresent(this.getError(errorCode, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the top-level ancestor of this control.
|
||||||
|
*/
|
||||||
get root(): AbstractControl {
|
get root(): AbstractControl {
|
||||||
let x: AbstractControl = this;
|
let x: AbstractControl = this;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user