diff --git a/goldens/circular-deps/packages.json b/goldens/circular-deps/packages.json index 8c26c0a489..2a042db5e6 100644 --- a/goldens/circular-deps/packages.json +++ b/goldens/circular-deps/packages.json @@ -1002,27 +1002,6 @@ "packages/core/testing/src/r3_test_bed.ts", "packages/core/testing/src/test_bed.ts" ], - [ - "packages/forms/src/directives/abstract_control_directive.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts" - ], - [ - "packages/forms/src/directives/abstract_control_directive.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/abstract_form_group_directive.ts", - "packages/forms/src/directives/control_container.ts" - ], - [ - "packages/forms/src/directives/abstract_control_directive.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/abstract_form_group_directive.ts", - "packages/forms/src/directives/control_container.ts", - "packages/forms/src/directives/form_interface.ts", - "packages/forms/src/directives/ng_control.ts" - ], [ "packages/forms/src/directives/abstract_form_group_directive.ts", "packages/forms/src/directives/control_container.ts", @@ -1030,10 +1009,7 @@ ], [ "packages/forms/src/directives/abstract_form_group_directive.ts", - "packages/forms/src/directives/control_container.ts", - "packages/forms/src/directives/form_interface.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts" + "packages/forms/src/directives/form_interface.ts" ], [ "packages/forms/src/directives/abstract_form_group_directive.ts", @@ -1041,13 +1017,59 @@ ], [ "packages/forms/src/directives/abstract_form_group_directive.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts" + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/control_container.ts", + "packages/forms/src/directives/form_interface.ts" ], [ + "packages/forms/src/directives/abstract_form_group_directive.ts", + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/ng_control.ts", "packages/forms/src/directives/control_container.ts", - "packages/forms/src/directives/form_interface.ts", - "packages/forms/src/directives/ng_control.ts" + "packages/forms/src/directives/form_interface.ts" + ], + [ + "packages/forms/src/directives/abstract_form_group_directive.ts", + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/reactive_directives/form_group_name.ts" + ], + [ + "packages/forms/src/directives/abstract_form_group_directive.ts", + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/reactive_directives/form_group_name.ts", + "packages/forms/src/directives/control_container.ts", + "packages/forms/src/directives/form_interface.ts" + ], + [ + "packages/forms/src/directives/abstract_form_group_directive.ts", + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/reactive_directives/form_group_name.ts", + "packages/forms/src/directives/reactive_directives/form_group_directive.ts", + "packages/forms/src/directives/control_container.ts", + "packages/forms/src/directives/form_interface.ts" + ], + [ + "packages/forms/src/directives/abstract_form_group_directive.ts", + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/reactive_directives/form_group_name.ts", + "packages/forms/src/directives/reactive_directives/form_group_directive.ts", + "packages/forms/src/directives/form_interface.ts" + ], + [ + "packages/forms/src/directives/abstract_form_group_directive.ts", + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/reactive_directives/form_group_name.ts", + "packages/forms/src/directives/reactive_directives/form_group_directive.ts", + "packages/forms/src/directives/reactive_directives/form_control_name.ts" + ], + [ + "packages/forms/src/directives/abstract_form_group_directive.ts", + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/reactive_directives/form_group_name.ts", + "packages/forms/src/directives/reactive_directives/form_group_directive.ts", + "packages/forms/src/directives/reactive_directives/form_control_name.ts", + "packages/forms/src/directives/control_container.ts", + "packages/forms/src/directives/form_interface.ts" ], [ "packages/forms/src/directives/ng_form.ts", @@ -1065,14 +1087,6 @@ "packages/forms/src/directives/reactive_directives/form_group_directive.ts", "packages/forms/src/directives/reactive_directives/form_control_name.ts" ], - [ - "packages/forms/src/directives/reactive_directives/form_control_directive.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/reactive_directives/form_group_name.ts", - "packages/forms/src/directives/reactive_directives/form_group_directive.ts", - "packages/forms/src/directives/reactive_directives/form_control_name.ts" - ], [ "packages/forms/src/directives/reactive_directives/form_control_name.ts", "packages/forms/src/directives/reactive_directives/form_group_directive.ts" @@ -1088,13 +1102,6 @@ "packages/forms/src/directives/reactive_directives/form_group_name.ts", "packages/forms/src/directives/reactive_directives/form_group_directive.ts" ], - [ - "packages/forms/src/directives/reactive_directives/form_control_name.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/reactive_directives/form_group_name.ts", - "packages/forms/src/directives/reactive_directives/form_group_directive.ts" - ], [ "packages/forms/src/directives/reactive_directives/form_group_directive.ts", "packages/forms/src/directives/reactive_directives/form_group_name.ts" @@ -1104,40 +1111,23 @@ "packages/forms/src/directives/shared.ts", "packages/forms/src/directives/reactive_directives/form_group_name.ts" ], - [ - "packages/forms/src/directives/reactive_directives/form_group_directive.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/reactive_directives/form_group_name.ts" - ], [ "packages/forms/src/directives/reactive_directives/form_group_name.ts", "packages/forms/src/directives/shared.ts" ], [ - "packages/forms/src/directives/reactive_directives/form_group_name.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts" - ], - [ - "packages/forms/src/directives/shared.ts", - "packages/forms/src/model.ts" - ], - [ - "packages/forms/src/directives/shared.ts", - "packages/forms/src/validators.ts", "packages/forms/src/directives/validators.ts", "packages/forms/src/model.ts" ], - [ - "packages/forms/src/directives/shared.ts", - "packages/forms/src/validators.ts", - "packages/forms/src/model.ts" - ], [ "packages/forms/src/directives/validators.ts", "packages/forms/src/validators.ts" ], + [ + "packages/forms/src/directives/validators.ts", + "packages/forms/src/validators.ts", + "packages/forms/src/model.ts" + ], [ "packages/language-service/src/completions.ts", "packages/language-service/src/template.ts", diff --git a/goldens/public-api/forms/forms.d.ts b/goldens/public-api/forms/forms.d.ts index 87df5fcc74..24129a6157 100644 --- a/goldens/public-api/forms/forms.d.ts +++ b/goldens/public-api/forms/forms.d.ts @@ -67,6 +67,7 @@ export declare abstract class AbstractControl { } export declare abstract class AbstractControlDirective { + get asyncValidator(): AsyncValidatorFn | null; abstract get control(): AbstractControl | null; get dirty(): boolean | null; get disabled(): boolean | null; @@ -81,6 +82,7 @@ export declare abstract class AbstractControlDirective { get touched(): boolean | null; get untouched(): boolean | null; get valid(): boolean | null; + get validator(): ValidatorFn | null; get value(): any; get valueChanges(): Observable | null; getError(errorCode: string, path?: Array | string): any; @@ -95,11 +97,9 @@ export declare interface AbstractControlOptions { } export declare class AbstractFormGroupDirective extends ControlContainer implements OnInit, OnDestroy { - get asyncValidator(): AsyncValidatorFn | null; get control(): FormGroup; get formDirective(): Form | null; get path(): string[]; - get validator(): ValidatorFn | null; ngOnDestroy(): void; ngOnInit(): void; } @@ -193,12 +193,10 @@ export declare class FormArray extends AbstractControl { } export declare class FormArrayName extends ControlContainer implements OnInit, OnDestroy { - get asyncValidator(): AsyncValidatorFn | null; get control(): FormArray; get formDirective(): FormGroupDirective | null; name: string | number | null; get path(): string[]; - get validator(): ValidatorFn | null; constructor(parent: ControlContainer, validators: (Validator | ValidatorFn)[], asyncValidators: (AsyncValidator | AsyncValidatorFn)[]); ngOnDestroy(): void; ngOnInit(): void; @@ -237,14 +235,12 @@ export declare class FormControl extends AbstractControl { } export declare class FormControlDirective extends NgControl implements OnChanges { - get asyncValidator(): AsyncValidatorFn | null; get control(): FormControl; form: FormControl; set isDisabled(isDisabled: boolean); /** @deprecated */ model: any; get path(): string[]; /** @deprecated */ update: EventEmitter; - get validator(): ValidatorFn | null; viewModel: any; constructor(validators: (Validator | ValidatorFn)[], asyncValidators: (AsyncValidator | AsyncValidatorFn)[], valueAccessors: ControlValueAccessor[], _ngModelWarningConfig: string | null); ngOnChanges(changes: SimpleChanges): void; @@ -252,7 +248,6 @@ export declare class FormControlDirective extends NgControl implements OnChanges } export declare class FormControlName extends NgControl implements OnChanges, OnDestroy { - get asyncValidator(): AsyncValidatorFn; readonly control: FormControl; get formDirective(): any; set isDisabled(isDisabled: boolean); @@ -260,7 +255,6 @@ export declare class FormControlName extends NgControl implements OnChanges, OnD name: string | number | null; get path(): string[]; /** @deprecated */ update: EventEmitter; - get validator(): ValidatorFn | null; constructor(parent: ControlContainer, validators: (Validator | ValidatorFn)[], asyncValidators: (AsyncValidator | AsyncValidatorFn)[], valueAccessors: ControlValueAccessor[], _ngModelWarningConfig: string | null); ngOnChanges(changes: SimpleChanges): void; ngOnDestroy(): void; @@ -306,7 +300,7 @@ export declare class FormGroupDirective extends ControlContainer implements Form ngSubmit: EventEmitter; get path(): string[]; readonly submitted: boolean; - constructor(_validators: (Validator | ValidatorFn)[], _asyncValidators: (AsyncValidator | AsyncValidatorFn)[]); + constructor(validators: (Validator | ValidatorFn)[], asyncValidators: (AsyncValidator | AsyncValidatorFn)[]); addControl(dir: FormControlName): FormControl; addFormArray(dir: FormArrayName): void; addFormGroup(dir: FormGroupName): void; @@ -352,9 +346,7 @@ export declare const NG_VALIDATORS: InjectionToken<(Function | Validator)[]>; export declare const NG_VALUE_ACCESSOR: InjectionToken; export declare abstract class NgControl extends AbstractControlDirective { - get asyncValidator(): AsyncValidatorFn | null; name: string | number | null; - get validator(): ValidatorFn | null; valueAccessor: ControlValueAccessor | null; abstract viewToModelUpdate(newValue: any): void; } @@ -398,7 +390,6 @@ export declare class NgForm extends ControlContainer implements Form, AfterViewI } export declare class NgModel extends NgControl implements OnChanges, OnDestroy { - get asyncValidator(): AsyncValidatorFn | null; readonly control: FormControl; get formDirective(): any; isDisabled: boolean; @@ -411,7 +402,6 @@ export declare class NgModel extends NgControl implements OnChanges, OnDestroy { }; get path(): string[]; update: EventEmitter; - get validator(): ValidatorFn | null; viewModel: any; constructor(parent: ControlContainer, validators: (Validator | ValidatorFn)[], asyncValidators: (AsyncValidator | AsyncValidatorFn)[], valueAccessors: ControlValueAccessor[]); ngOnChanges(changes: SimpleChanges): void; diff --git a/packages/forms/src/directives/abstract_control_directive.ts b/packages/forms/src/directives/abstract_control_directive.ts index 54e5eeeace..e8f07b55ad 100644 --- a/packages/forms/src/directives/abstract_control_directive.ts +++ b/packages/forms/src/directives/abstract_control_directive.ts @@ -7,8 +7,12 @@ */ import {Observable} from 'rxjs'; + import {AbstractControl} from '../model'; -import {ValidationErrors} from './validators'; +import {composeAsyncValidators, composeValidators} from '../validators'; + +import {AsyncValidator, AsyncValidatorFn, ValidationErrors, Validator, ValidatorFn} from './validators'; + /** * @description @@ -165,6 +169,67 @@ export abstract class AbstractControlDirective { return null; } + /** + * Contains the result of merging synchronous validators into a single validator function + * (combined using `Validators.compose`). + */ + private _composedValidatorFn: ValidatorFn|null|undefined; + + /** + * Contains the result of merging asynchronous validators into a single validator function + * (combined using `Validators.composeAsync`). + */ + private _composedAsyncValidatorFn: AsyncValidatorFn|null|undefined; + + /** + * Set of synchronous validators as they were provided while calling `setValidators` function. + * @internal + */ + _rawValidators: Array = []; + + /** + * Set of asynchronous validators as they were provided while calling `setAsyncValidators` + * function. + * @internal + */ + _rawAsyncValidators: Array = []; + + /** + * Sets synchronous validators for this directive. + * @internal + */ + _setValidators(validators: Array|undefined): void { + this._rawValidators = validators || []; + this._composedValidatorFn = composeValidators(this._rawValidators); + } + + /** + * Sets asynchronous validators for this directive. + * @internal + */ + _setAsyncValidators(validators: Array|undefined): void { + this._rawAsyncValidators = validators || []; + this._composedAsyncValidatorFn = composeAsyncValidators(this._rawAsyncValidators); + } + + /** + * @description + * Synchronous validator function composed of all the synchronous validators registered with this + * directive. + */ + get validator(): ValidatorFn|null { + return this._composedValidatorFn || null; + } + + /** + * @description + * Asynchronous validator function composed of all the asynchronous validators registered with + * this directive. + */ + get asyncValidator(): AsyncValidatorFn|null { + return this._composedAsyncValidatorFn || null; + } + /** * @description * Resets the control with the provided value if the control is present. diff --git a/packages/forms/src/directives/abstract_form_group_directive.ts b/packages/forms/src/directives/abstract_form_group_directive.ts index 5519221902..d5497344ec 100644 --- a/packages/forms/src/directives/abstract_form_group_directive.ts +++ b/packages/forms/src/directives/abstract_form_group_directive.ts @@ -12,8 +12,7 @@ import {FormGroup} from '../model'; import {ControlContainer} from './control_container'; import {Form} from './form_interface'; -import {composeAsyncValidators, composeValidators, controlPath} from './shared'; -import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators'; +import {controlPath} from './shared'; @@ -34,24 +33,6 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn // TODO(issue/24571): remove '!'. _parent!: ControlContainer; - /** - * @description - * An array of synchronous validators for the group - * - * @internal - */ - // TODO(issue/24571): remove '!'. - _validators!: (Validator|ValidatorFn)[]; - - /** - * @description - * An array of async validators for the group - * - * @internal - */ - // TODO(issue/24571): remove '!'. - _asyncValidators!: (AsyncValidator|AsyncValidatorFn)[]; - /** @nodoc */ ngOnInit(): void { this._checkParentType(); @@ -91,22 +72,6 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn return this._parent ? this._parent.formDirective : null; } - /** - * @description - * The synchronous validators registered with this group. - */ - get validator(): ValidatorFn|null { - return composeValidators(this._validators); - } - - /** - * @description - * The async validators registered with this group. - */ - get asyncValidator(): AsyncValidatorFn|null { - return composeAsyncValidators(this._asyncValidators); - } - /** @internal */ _checkParentType(): void {} } diff --git a/packages/forms/src/directives/ng_control.ts b/packages/forms/src/directives/ng_control.ts index 23cb4edfd0..f9234624d2 100644 --- a/packages/forms/src/directives/ng_control.ts +++ b/packages/forms/src/directives/ng_control.ts @@ -6,17 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ - import {AbstractControlDirective} from './abstract_control_directive'; import {ControlContainer} from './control_container'; import {ControlValueAccessor} from './control_value_accessor'; -import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators'; -function unimplemented(): any { - if (typeof ngDevMode === 'undefined' || ngDevMode) { - throw new Error('unimplemented'); - } -} /** * @description @@ -46,42 +39,6 @@ export abstract class NgControl extends AbstractControlDirective { */ valueAccessor: ControlValueAccessor|null = null; - /** - * @description - * The uncomposed array of synchronous validators for the control - * - * @internal - */ - _rawValidators: Array = []; - - /** - * @description - * The uncomposed array of async validators for the control - * - * @internal - */ - _rawAsyncValidators: Array = []; - - /** - * @description - * The registered synchronous validator function for the control - * - * @throws An exception that this method is not implemented - */ - get validator(): ValidatorFn|null { - return unimplemented(); - } - - /** - * @description - * The registered async validator function for the control - * - * @throws An exception that this method is not implemented - */ - get asyncValidator(): AsyncValidatorFn|null { - return unimplemented(); - } - /** * @description * The callback method to update the model from the view when requested diff --git a/packages/forms/src/directives/ng_form.ts b/packages/forms/src/directives/ng_form.ts index c221aae8fa..ffb1593250 100644 --- a/packages/forms/src/directives/ng_form.ts +++ b/packages/forms/src/directives/ng_form.ts @@ -9,14 +9,14 @@ import {AfterViewInit, Directive, EventEmitter, forwardRef, Inject, Input, Optional, Self} from '@angular/core'; import {AbstractControl, FormControl, FormGroup, FormHooks} from '../model'; -import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators'; +import {composeAsyncValidators, composeValidators, NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators'; import {ControlContainer} from './control_container'; import {Form} from './form_interface'; import {NgControl} from './ng_control'; import {NgModel} from './ng_model'; import {NgModelGroup} from './ng_model_group'; -import {composeAsyncValidators, composeValidators, removeDir, setUpControl, setUpFormContainer, syncPendingControls} from './shared'; +import {removeDir, setUpControl, setUpFormContainer, syncPendingControls} from './shared'; import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators'; export const formDirectiveProvider: any = { diff --git a/packages/forms/src/directives/ng_model.ts b/packages/forms/src/directives/ng_model.ts index ae7a434332..6cd329877b 100644 --- a/packages/forms/src/directives/ng_model.ts +++ b/packages/forms/src/directives/ng_model.ts @@ -17,7 +17,7 @@ import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor' import {NgControl} from './ng_control'; import {NgForm} from './ng_form'; import {NgModelGroup} from './ng_model_group'; -import {composeAsyncValidators, composeValidators, controlPath, isPropertyUpdated, selectValueAccessor, setUpControl} from './shared'; +import {controlPath, isPropertyUpdated, selectValueAccessor, setUpControl} from './shared'; import {TemplateDrivenErrors} from './template_driven_errors'; import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators'; @@ -208,8 +208,8 @@ export class NgModel extends NgControl implements OnChanges, OnDestroy { @Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) { super(); this._parent = parent; - this._rawValidators = validators || []; - this._rawAsyncValidators = asyncValidators || []; + this._setValidators(validators); + this._setAsyncValidators(asyncValidators); this.valueAccessor = selectValueAccessor(this, valueAccessors); } @@ -249,24 +249,6 @@ export class NgModel extends NgControl implements OnChanges, OnDestroy { return this._parent ? this._parent.formDirective : null; } - /** - * @description - * Synchronous validator function composed of all the synchronous validators - * registered with this directive. - */ - get validator(): ValidatorFn|null { - return composeValidators(this._rawValidators); - } - - /** - * @description - * Async validator function composed of all the async validators registered with this - * directive. - */ - get asyncValidator(): AsyncValidatorFn|null { - return composeAsyncValidators(this._rawAsyncValidators); - } - /** * @description * Sets the new value for the view model and emits an `ngModelChange` event. diff --git a/packages/forms/src/directives/ng_model_group.ts b/packages/forms/src/directives/ng_model_group.ts index 6618cdc179..434a4de918 100644 --- a/packages/forms/src/directives/ng_model_group.ts +++ b/packages/forms/src/directives/ng_model_group.ts @@ -64,8 +64,8 @@ export class NgModelGroup extends AbstractFormGroupDirective implements OnInit, (AsyncValidator|AsyncValidatorFn)[]) { super(); this._parent = parent; - this._validators = validators; - this._asyncValidators = asyncValidators; + this._setValidators(validators); + this._setAsyncValidators(asyncValidators); } /** @internal */ diff --git a/packages/forms/src/directives/reactive_directives/form_control_directive.ts b/packages/forms/src/directives/reactive_directives/form_control_directive.ts index 05d9565d6d..547ea216d1 100644 --- a/packages/forms/src/directives/reactive_directives/form_control_directive.ts +++ b/packages/forms/src/directives/reactive_directives/form_control_directive.ts @@ -13,7 +13,7 @@ import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '../control_value_accessor'; import {NgControl} from '../ng_control'; import {ReactiveErrors} from '../reactive_errors'; -import {_ngModelWarning, composeAsyncValidators, composeValidators, isPropertyUpdated, selectValueAccessor, setUpControl} from '../shared'; +import {_ngModelWarning, isPropertyUpdated, selectValueAccessor, setUpControl} from '../shared'; import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from '../validators'; @@ -51,7 +51,6 @@ export const formControlBinding: any = { * @publicApi */ @Directive({selector: '[formControl]', providers: [formControlBinding], exportAs: 'ngForm'}) - export class FormControlDirective extends NgControl implements OnChanges { /** * Internal reference to the view model value. @@ -111,8 +110,8 @@ export class FormControlDirective extends NgControl implements OnChanges { @Optional() @Inject(NG_MODEL_WITH_FORM_CONTROL_WARNING) private _ngModelWarningConfig: string| null) { super(); - this._rawValidators = validators || []; - this._rawAsyncValidators = asyncValidators || []; + this._setValidators(validators); + this._setAsyncValidators(asyncValidators); this.valueAccessor = selectValueAccessor(this, valueAccessors); } @@ -141,24 +140,6 @@ export class FormControlDirective extends NgControl implements OnChanges { return []; } - /** - * @description - * Synchronous validator function composed of all the synchronous validators - * registered with this directive. - */ - get validator(): ValidatorFn|null { - return composeValidators(this._rawValidators); - } - - /** - * @description - * Async validator function composed of all the async validators registered with this - * directive. - */ - get asyncValidator(): AsyncValidatorFn|null { - return composeAsyncValidators(this._rawAsyncValidators); - } - /** * @description * The `FormControl` bound to this directive. diff --git a/packages/forms/src/directives/reactive_directives/form_control_name.ts b/packages/forms/src/directives/reactive_directives/form_control_name.ts index e2d3fc65a2..9e76a3f91a 100644 --- a/packages/forms/src/directives/reactive_directives/form_control_name.ts +++ b/packages/forms/src/directives/reactive_directives/form_control_name.ts @@ -15,7 +15,7 @@ import {ControlContainer} from '../control_container'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '../control_value_accessor'; import {NgControl} from '../ng_control'; import {ReactiveErrors} from '../reactive_errors'; -import {_ngModelWarning, composeAsyncValidators, composeValidators, controlPath, isPropertyUpdated, selectValueAccessor} from '../shared'; +import {_ngModelWarning, controlPath, isPropertyUpdated, selectValueAccessor} from '../shared'; import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from '../validators'; import {NG_MODEL_WITH_FORM_CONTROL_WARNING} from './form_control_directive'; @@ -136,8 +136,8 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy { null) { super(); this._parent = parent; - this._rawValidators = validators || []; - this._rawAsyncValidators = asyncValidators || []; + this._setValidators(validators); + this._setAsyncValidators(asyncValidators); this.valueAccessor = selectValueAccessor(this, valueAccessors); } @@ -186,24 +186,6 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy { return this._parent ? this._parent.formDirective : null; } - /** - * @description - * Synchronous validator function composed of all the synchronous validators - * registered with this directive. - */ - get validator(): ValidatorFn|null { - return composeValidators(this._rawValidators); - } - - /** - * @description - * Async validator function composed of all the async validators registered with this - * directive. - */ - get asyncValidator(): AsyncValidatorFn { - return composeAsyncValidators(this._rawAsyncValidators)!; - } - private _checkParentType(): void { if (typeof ngDevMode === 'undefined' || ngDevMode) { if (!(this._parent instanceof FormGroupName) && diff --git a/packages/forms/src/directives/reactive_directives/form_group_directive.ts b/packages/forms/src/directives/reactive_directives/form_group_directive.ts index babb9b091b..f0651cfe83 100644 --- a/packages/forms/src/directives/reactive_directives/form_group_directive.ts +++ b/packages/forms/src/directives/reactive_directives/form_group_directive.ts @@ -13,7 +13,7 @@ import {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from '../../validators'; import {ControlContainer} from '../control_container'; import {Form} from '../form_interface'; import {ReactiveErrors} from '../reactive_errors'; -import {cleanUpControl, composeAsyncValidators, composeValidators, removeDir, setUpControl, setUpFormContainer, syncPendingControls} from '../shared'; +import {cleanUpControl, removeDir, setUpControl, setUpFormContainer, syncPendingControls} from '../shared'; import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from '../validators'; import {FormControlName} from './form_control_name'; @@ -82,10 +82,12 @@ export class FormGroupDirective extends ControlContainer implements Form, OnChan @Output() ngSubmit = new EventEmitter(); constructor( - @Optional() @Self() @Inject(NG_VALIDATORS) private _validators: (Validator|ValidatorFn)[], - @Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: + @Optional() @Self() @Inject(NG_VALIDATORS) private validators: (Validator|ValidatorFn)[], + @Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) private asyncValidators: (AsyncValidator|AsyncValidatorFn)[]) { super(); + this._setValidators(validators); + this._setAsyncValidators(asyncValidators); } /** @nodoc */ @@ -280,11 +282,9 @@ export class FormGroupDirective extends ControlContainer implements Form, OnChan } private _updateValidators() { - const sync = composeValidators(this._validators); - this.form.validator = Validators.compose([this.form.validator!, sync!]); - - const async = composeAsyncValidators(this._asyncValidators); - this.form.asyncValidator = Validators.composeAsync([this.form.asyncValidator!, async!]); + this.form.validator = Validators.compose([this.form.validator, this.validator]); + this.form.asyncValidator = + Validators.composeAsync([this.form.asyncValidator, this.asyncValidator]); } private _checkFormPresent() { diff --git a/packages/forms/src/directives/reactive_directives/form_group_name.ts b/packages/forms/src/directives/reactive_directives/form_group_name.ts index 3cc056c3b9..b941e65e72 100644 --- a/packages/forms/src/directives/reactive_directives/form_group_name.ts +++ b/packages/forms/src/directives/reactive_directives/form_group_name.ts @@ -13,7 +13,7 @@ import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators'; import {AbstractFormGroupDirective} from '../abstract_form_group_directive'; import {ControlContainer} from '../control_container'; import {ReactiveErrors} from '../reactive_errors'; -import {composeAsyncValidators, composeValidators, controlPath} from '../shared'; +import {controlPath} from '../shared'; import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from '../validators'; import {FormGroupDirective} from './form_group_directive'; @@ -91,8 +91,8 @@ export class FormGroupName extends AbstractFormGroupDirective implements OnInit, (AsyncValidator|AsyncValidatorFn)[]) { super(); this._parent = parent; - this._validators = validators; - this._asyncValidators = asyncValidators; + this._setValidators(validators); + this._setAsyncValidators(asyncValidators); } /** @internal */ @@ -137,12 +137,6 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy /** @internal */ _parent: ControlContainer; - /** @internal */ - _validators: (Validator|ValidatorFn)[]; - - /** @internal */ - _asyncValidators: (AsyncValidator|AsyncValidatorFn)[]; - /** * @description * Tracks the name of the `FormArray` bound to the directive. The name corresponds @@ -162,8 +156,8 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy (AsyncValidator|AsyncValidatorFn)[]) { super(); this._parent = parent; - this._validators = validators; - this._asyncValidators = asyncValidators; + this._setValidators(validators); + this._setAsyncValidators(asyncValidators); } /** @@ -211,23 +205,6 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy return controlPath(this.name == null ? this.name : this.name.toString(), this._parent); } - /** - * @description - * Synchronous validator function composed of all the synchronous validators registered with this - * directive. - */ - get validator(): ValidatorFn|null { - return composeValidators(this._validators); - } - - /** - * @description - * Async validator function composed of all the async validators registered with this directive. - */ - get asyncValidator(): AsyncValidatorFn|null { - return composeAsyncValidators(this._asyncValidators); - } - private _checkParentType(): void { if (_hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) { ReactiveErrors.arrayParentException(); diff --git a/packages/forms/src/directives/shared.ts b/packages/forms/src/directives/shared.ts index a3dcce5616..3cb78e8c1b 100644 --- a/packages/forms/src/directives/shared.ts +++ b/packages/forms/src/directives/shared.ts @@ -9,7 +9,7 @@ import {isDevMode} from '@angular/core'; import {FormArray, FormControl, FormGroup} from '../model'; -import {normalizeValidators, Validators} from '../validators'; +import {Validators} from '../validators'; import {AbstractControlDirective} from './abstract_control_directive'; import {AbstractFormGroupDirective} from './abstract_form_group_directive'; @@ -150,18 +150,6 @@ function _throwError(dir: AbstractControlDirective, message: string): void { throw new Error(`${message} ${messageEnd}`); } -export function composeValidators(validators: Array): ValidatorFn|null { - return validators != null ? Validators.compose(normalizeValidators(validators)) : - null; -} - -export function composeAsyncValidators(validators: Array): - AsyncValidatorFn|null { - return validators != null ? - Validators.composeAsync(normalizeValidators(validators)) : - null; -} - export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any): boolean { if (!changes.hasOwnProperty('model')) return false; const change = changes['model']; diff --git a/packages/forms/src/model.ts b/packages/forms/src/model.ts index e3356e5726..40d45d39a6 100644 --- a/packages/forms/src/model.ts +++ b/packages/forms/src/model.ts @@ -8,9 +8,9 @@ import {EventEmitter} from '@angular/core'; import {Observable} from 'rxjs'; -import {composeAsyncValidators, composeValidators} from './directives/shared'; + import {AsyncValidatorFn, ValidationErrors, ValidatorFn} from './directives/validators'; -import {toObservable} from './validators'; +import {composeAsyncValidators, composeValidators, toObservable} from './validators'; /** * Reports that a FormControl is valid, meaning that no errors exist in the input value. diff --git a/packages/forms/src/validators.ts b/packages/forms/src/validators.ts index 38f247dda2..5ebf86ce7a 100644 --- a/packages/forms/src/validators.ts +++ b/packages/forms/src/validators.ts @@ -531,4 +531,24 @@ export function normalizeValidators(validators: (V|Validator|AsyncValidator)[ validator : ((c: AbstractControl) => validator.validate(c)) as unknown as V; }); +} + +/** + * Merges synchronous validators into a single validator function (combined using + * `Validators.compose`). + */ +export function composeValidators(validators: Array): ValidatorFn|null { + return validators != null ? Validators.compose(normalizeValidators(validators)) : + null; +} + +/** + * Merges asynchronous validators into a single validator function (combined using + * `Validators.composeAsync`). + */ +export function composeAsyncValidators(validators: Array): + AsyncValidatorFn|null { + return validators != null ? + Validators.composeAsync(normalizeValidators(validators)) : + null; } \ No newline at end of file diff --git a/packages/forms/test/directives_spec.ts b/packages/forms/test/directives_spec.ts index 419ca1e413..2b99f910e1 100644 --- a/packages/forms/test/directives_spec.ts +++ b/packages/forms/test/directives_spec.ts @@ -10,7 +10,8 @@ import {SimpleChange} from '@angular/core'; import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal'; import {AbstractControl, CheckboxControlValueAccessor, ControlValueAccessor, DefaultValueAccessor, FormArray, FormArrayName, FormControl, FormControlDirective, FormControlName, FormGroup, FormGroupDirective, FormGroupName, NgControl, NgForm, NgModel, NgModelGroup, SelectControlValueAccessor, SelectMultipleControlValueAccessor, ValidationErrors, Validator, Validators} from '@angular/forms'; -import {composeValidators, selectValueAccessor} from '@angular/forms/src/directives/shared'; +import {selectValueAccessor} from '@angular/forms/src/directives/shared'; +import {composeValidators} from '@angular/forms/src/validators'; import {SpyNgControl, SpyValueAccessor} from './spies'; import {asyncValidator} from './util';