diff --git a/goldens/public-api/forms/index.md b/goldens/public-api/forms/index.md index 6bb84d0cd18..f66b89b9490 100644 --- a/goldens/public-api/forms/index.md +++ b/goldens/public-api/forms/index.md @@ -285,6 +285,8 @@ export class FormBuilder { control(formState: T | FormControlState, opts: FormControlOptions & { nonNullable: true; }): FormControl; + // @deprecated (undocumented) + control(formState: T | FormControlState, opts: FormControlOptions, asyncValidator: AsyncValidatorFn | AsyncValidatorFn[]): FormControl; // (undocumented) control(formState: T | FormControlState, validatorOrOpts?: ValidatorFn | ValidatorFn[] | FormControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null): FormControl; group(controls: T, options?: AbstractControlOptions | null): FormGroup<{ diff --git a/packages/forms/src/directives/reactive_errors.ts b/packages/forms/src/directives/reactive_errors.ts index 23743b5f6b2..a9e00d41c32 100644 --- a/packages/forms/src/directives/reactive_errors.ts +++ b/packages/forms/src/directives/reactive_errors.ts @@ -73,6 +73,22 @@ export const disabledAttrWarning = ` }); `; +export const asyncValidatorsDroppedWithOptsWarning = ` + It looks like you're constructing using a FormControl with both an options argument and an + async validators argument. Mixing these arguments will cause your async validators to be dropped. + You should either put all your validators in the options object, or in separate validators + arguments. For example: + + // Using validators arguments + fc = new FormControl(42, Validators.required, myAsyncValidator); + + // Using AbstractControlOptions + fc = new FormControl(42, {validators: Validators.required, asyncValidators: myAV}); + + // Do NOT mix them: async validators will be dropped! + fc = new FormControl(42, {validators: Validators.required}, /* Oops! */ myAsyncValidator); +`; + export function ngModelWarning(directiveName: string): string { return ` It looks like you're using ngModel on the same form field as ${directiveName}. diff --git a/packages/forms/src/form_builder.ts b/packages/forms/src/form_builder.ts index d1896a43650..d27b071772e 100644 --- a/packages/forms/src/form_builder.ts +++ b/packages/forms/src/form_builder.ts @@ -214,6 +214,13 @@ export class FormBuilder { control(formState: T|FormControlState, opts: FormControlOptions&{nonNullable: true}): FormControl; + /** + * @deprecated When passing an `options` argument, the `asyncValidator` argument has no effect. + */ + control( + formState: T|FormControlState, opts: FormControlOptions, + asyncValidator: AsyncValidatorFn|AsyncValidatorFn[]): FormControl; + control( formState: T|FormControlState, validatorOrOpts?: ValidatorFn|ValidatorFn[]|FormControlOptions|null, diff --git a/packages/forms/src/model/abstract_model.ts b/packages/forms/src/model/abstract_model.ts index 95866fecb71..6cced082ee8 100644 --- a/packages/forms/src/model/abstract_model.ts +++ b/packages/forms/src/model/abstract_model.ts @@ -9,7 +9,7 @@ import {EventEmitter, ɵRuntimeError as RuntimeError} from '@angular/core'; import {Observable} from 'rxjs'; -import {missingControlError, missingControlValueError, noControlsError} from '../directives/reactive_errors'; +import {asyncValidatorsDroppedWithOptsWarning, missingControlError, missingControlValueError, noControlsError} from '../directives/reactive_errors'; import {AsyncValidatorFn, ValidationErrors, ValidatorFn} from '../directives/validators'; import {RuntimeErrorCode} from '../errors'; import {FormArray, FormGroup} from '../forms'; @@ -88,6 +88,11 @@ export function pickAsyncValidators( asyncValidator?: AsyncValidatorFn|AsyncValidatorFn[]|null, validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null): AsyncValidatorFn| AsyncValidatorFn[]|null { + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (isOptionsObj(validatorOrOpts) && asyncValidator) { + console.warn(asyncValidatorsDroppedWithOptsWarning); + } + } return (isOptionsObj(validatorOrOpts) ? validatorOrOpts.asyncValidators : asyncValidator) || null; } diff --git a/packages/forms/src/model/form_control.ts b/packages/forms/src/model/form_control.ts index 1002b597816..bfe5400183b 100644 --- a/packages/forms/src/model/form_control.ts +++ b/packages/forms/src/model/form_control.ts @@ -375,12 +375,21 @@ export interface ɵFormControlCtor { */ new(value: FormControlState|T, opts: FormControlOptions&{nonNullable: true}): FormControl; + /** * @deprecated Use `nonNullable` instead. */ new(value: FormControlState|T, opts: FormControlOptions&{ initialValueIsDefault: true }): FormControl; + + /** + * @deprecated When passing an `options` argument, the `asyncValidator` argument has no effect. + */ + new( + value: FormControlState|T, opts: FormControlOptions, + asyncValidator: AsyncValidatorFn|AsyncValidatorFn[]): FormControl; + new( value: FormControlState|T, validatorOrOpts?: ValidatorFn|ValidatorFn[]|FormControlOptions|null,