Skip to content

feat(forms): add addValidators and hasValidators methods to AbstractControl #42838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions goldens/public-api/forms/forms.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { Version } from '@angular/core';
// @public
export abstract class AbstractControl {
constructor(validators: ValidatorFn | ValidatorFn[] | null, asyncValidators: AsyncValidatorFn | AsyncValidatorFn[] | null);
addAsyncValidators(validators: AsyncValidatorFn | AsyncValidatorFn[]): void;
addValidators(validators: ValidatorFn | ValidatorFn[]): void;
get asyncValidator(): AsyncValidatorFn | null;
set asyncValidator(asyncValidatorFn: AsyncValidatorFn | null);
clearAsyncValidators(): void;
Expand All @@ -39,7 +41,9 @@ export abstract class AbstractControl {
readonly errors: ValidationErrors | null;
get(path: Array<string | number> | string): AbstractControl | null;
getError(errorCode: string, path?: Array<string | number> | string): any;
hasAsyncValidator(validator: AsyncValidatorFn): boolean;
hasError(errorCode: string, path?: Array<string | number> | string): boolean;
hasValidator(validator: ValidatorFn): boolean;
get invalid(): boolean;
markAllAsTouched(): void;
markAsDirty(opts?: {
Expand All @@ -62,15 +66,17 @@ export abstract class AbstractControl {
abstract patchValue(value: any, options?: Object): void;
get pending(): boolean;
readonly pristine: boolean;
removeAsyncValidators(validators: AsyncValidatorFn | AsyncValidatorFn[]): void;
removeValidators(validators: ValidatorFn | ValidatorFn[]): void;
abstract reset(value?: any, options?: Object): void;
get root(): AbstractControl;
setAsyncValidators(newValidator: AsyncValidatorFn | AsyncValidatorFn[] | null): void;
setAsyncValidators(validators: AsyncValidatorFn | AsyncValidatorFn[] | null): void;
setErrors(errors: ValidationErrors | null, opts?: {
emitEvent?: boolean;
}): void;
// (undocumented)
setParent(parent: FormGroup | FormArray): void;
setValidators(newValidator: ValidatorFn | ValidatorFn[] | null): void;
setValidators(validators: ValidatorFn | ValidatorFn[] | null): void;
abstract setValue(value: any, options?: Object): void;
readonly status: string;
readonly statusChanges: Observable<any>;
Expand Down Expand Up @@ -384,7 +390,7 @@ export class FormGroupDirective extends ControlContainer implements Form, OnChan
resetForm(value?: any): void;
readonly submitted: boolean;
updateModel(dir: FormControlName, value: any): void;
}
}

// @public
export class FormGroupName extends AbstractFormGroupDirective implements OnInit, OnDestroy {
Expand All @@ -403,7 +409,7 @@ export class MaxLengthValidator implements Validator, OnChanges {
ngOnChanges(changes: SimpleChanges): void;
registerOnValidatorChange(fn: () => void): void;
validate(control: AbstractControl): ValidationErrors | null;
}
}

// @public
export class MaxValidator extends AbstractValidatorDirective implements OnChanges {
Expand All @@ -418,7 +424,7 @@ export class MinLengthValidator implements Validator, OnChanges {
ngOnChanges(changes: SimpleChanges): void;
registerOnValidatorChange(fn: () => void): void;
validate(control: AbstractControl): ValidationErrors | null;
}
}

// @public
export class MinValidator extends AbstractValidatorDirective implements OnChanges {
Expand Down Expand Up @@ -539,7 +545,7 @@ export class PatternValidator implements Validator, OnChanges {
pattern: string | RegExp;
registerOnValidatorChange(fn: () => void): void;
validate(control: AbstractControl): ValidationErrors | null;
}
}

// @public
export class RadioControlValueAccessor extends ɵangular_packages_forms_forms_g implements ControlValueAccessor, OnDestroy, OnInit {
Expand Down Expand Up @@ -632,7 +638,6 @@ export class Validators {
// @public (undocumented)
export const VERSION: Version;


// (No @packageDocumentation comment for this package)

```
2 changes: 1 addition & 1 deletion goldens/size-tracking/integration-payloads.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 1150,
"main-es2015": 162346,
"main-es2015": 163007,
"polyfills-es2015": 36975
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,9 @@
{
"name": "addToViewTree"
},
{
"name": "addValidators"
},
{
"name": "allocExpando"
},
Expand Down Expand Up @@ -1082,6 +1085,9 @@
{
"name": "hasValidLength"
},
{
"name": "hasValidator"
},
{
"name": "hostReportError"
},
Expand Down Expand Up @@ -1271,6 +1277,9 @@
{
"name": "makeRecord"
},
{
"name": "makeValidatorsArray"
},
{
"name": "map"
},
Expand Down Expand Up @@ -1430,6 +1439,9 @@
{
"name": "removeStyle"
},
{
"name": "removeValidators"
},
{
"name": "renderComponent"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,9 @@
{
"name": "addToViewTree"
},
{
"name": "addValidators"
},
{
"name": "allocExpando"
},
Expand Down Expand Up @@ -1046,6 +1049,9 @@
{
"name": "hasTagAndTypeMatch"
},
{
"name": "hasValidator"
},
{
"name": "hostReportError"
},
Expand Down Expand Up @@ -1232,6 +1238,9 @@
{
"name": "makeRecord"
},
{
"name": "makeValidatorsArray"
},
{
"name": "map"
},
Expand Down Expand Up @@ -1394,6 +1403,9 @@
{
"name": "removeStyle"
},
{
"name": "removeValidators"
},
{
"name": "renderComponent"
},
Expand Down
122 changes: 106 additions & 16 deletions packages/forms/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {Observable} from 'rxjs';

import {removeListItem} from './directives/shared';
import {AsyncValidatorFn, ValidationErrors, ValidatorFn} from './directives/validators';
import {composeAsyncValidators, composeValidators, toObservable} from './validators';
import {addValidators, composeAsyncValidators, composeValidators, hasValidator, makeValidatorsArray, removeValidators, toObservable} from './validators';

/**
* Reports that a FormControl is valid, meaning that no errors exist in the input value.
Expand Down Expand Up @@ -129,14 +129,12 @@ export interface AbstractControlOptions {
updateOn?: 'change'|'blur'|'submit';
}


function isOptionsObj(validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|
null): validatorOrOpts is AbstractControlOptions {
return validatorOrOpts != null && !Array.isArray(validatorOrOpts) &&
typeof validatorOrOpts === 'object';
}


/**
* This is the base class for `FormControl`, `FormGroup`, and `FormArray`.
*
Expand Down Expand Up @@ -245,7 +243,9 @@ export abstract class AbstractControl {
}

/**
* The function that is used to determine the validity of this control synchronously.
* 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(): ValidatorFn|null {
return this._composedValidatorFn;
Expand All @@ -255,7 +255,9 @@ export abstract class AbstractControl {
}

/**
* The function that is used to determine the validity of this control asynchronously.
* 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(): AsyncValidatorFn|null {
return this._composedAsyncValidatorFn;
Expand Down Expand Up @@ -425,32 +427,120 @@ export abstract class AbstractControl {

/**
* Sets the synchronous validators that are active on this control. Calling
* this overwrites any existing sync validators.
* 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: ValidatorFn|ValidatorFn[]|null): void {
this._rawValidators = validators;
this._composedValidatorFn = coerceToValidator(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: AsyncValidatorFn|AsyncValidatorFn[]|null): void {
this._rawAsyncValidators = validators;
this._composedAsyncValidatorFn = coerceToAsyncValidator(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: ValidatorFn|ValidatorFn[]): void {
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: AsyncValidatorFn|AsyncValidatorFn[]): void {
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.
*
* 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.
*/
setValidators(newValidator: ValidatorFn|ValidatorFn[]|null): void {
this._rawValidators = newValidator;
this._composedValidatorFn = coerceToValidator(newValidator);
removeValidators(validators: ValidatorFn|ValidatorFn[]): void {
this.setValidators(removeValidators(validators, this._rawValidators));
}

/**
* Sets the async validators that are active on this control. Calling this
* overwrites any existing async validators.
* 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: AsyncValidatorFn|AsyncValidatorFn[]): void {
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.
*
* @param validator The validator to check for presence. Compared by function reference.
* @returns Whether the provided validator was found on this control.
*/
hasValidator(validator: ValidatorFn): boolean {
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.
*/
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]|null): void {
this._rawAsyncValidators = newValidator;
this._composedAsyncValidatorFn = coerceToAsyncValidator(newValidator);
hasAsyncValidator(validator: AsyncValidatorFn): boolean {
return hasValidator(this._rawAsyncValidators, validator);
}

/**
* Empties out the sync validator list.
* 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.
Expand Down Expand Up @@ -1065,7 +1155,7 @@ export abstract class AbstractControl {
* console.log(control.status); // 'DISABLED'
* ```
*
* The following example initializes the control with a sync validator.
* The following example initializes the control with a synchronous validator.
*
* ```ts
* const control = new FormControl('', Validators.required);
Expand Down
Loading