diff --git a/packages/core/test/bundling/forms/bundle.golden_symbols.json b/packages/core/test/bundling/forms/bundle.golden_symbols.json index 53a49c913c..037046f00d 100644 --- a/packages/core/test/bundling/forms/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms/bundle.golden_symbols.json @@ -221,15 +221,6 @@ { "name": "FormControlName" }, - { - "name": "FormErrorExamples_formControlName" - }, - { - "name": "FormErrorExamples_formGroupName" - }, - { - "name": "FormErrorExamples_ngModelGroup" - }, { "name": "FormGroup" }, @@ -497,9 +488,6 @@ { "name": "RangeValueAccessor" }, - { - "name": "ReactiveErrors" - }, { "name": "ReactiveFormsComponent" }, @@ -608,9 +596,6 @@ { "name": "TRANSITION_ID" }, - { - "name": "TemplateDrivenErrors" - }, { "name": "TemplateFormsComponent" }, @@ -701,9 +686,6 @@ { "name": "_keyMap" }, - { - "name": "_noControlError" - }, { "name": "_randomChar" }, @@ -716,9 +698,6 @@ { "name": "_testabilityGetter" }, - { - "name": "_throwError" - }, { "name": "addComponentLogic" }, @@ -1628,9 +1607,6 @@ { "name": "u" }, - { - "name": "unimplemented" - }, { "name": "unwrapRNode" }, diff --git a/packages/forms/src/directives/ng_control.ts b/packages/forms/src/directives/ng_control.ts index 95fe13f589..23cb4edfd0 100644 --- a/packages/forms/src/directives/ng_control.ts +++ b/packages/forms/src/directives/ng_control.ts @@ -13,7 +13,9 @@ import {ControlValueAccessor} from './control_value_accessor'; import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators'; function unimplemented(): any { - throw new Error('unimplemented'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + throw new Error('unimplemented'); + } } /** diff --git a/packages/forms/src/directives/ng_model.ts b/packages/forms/src/directives/ng_model.ts index cc115be32e..73a1ac6ae5 100644 --- a/packages/forms/src/directives/ng_model.ts +++ b/packages/forms/src/directives/ng_model.ts @@ -317,18 +317,20 @@ export class NgModel extends NgControl implements OnChanges, OnDestroy { } private _checkParentType(): void { - if (!(this._parent instanceof NgModelGroup) && - this._parent instanceof AbstractFormGroupDirective) { - TemplateDrivenErrors.formGroupNameException(); - } else if (!(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm)) { - TemplateDrivenErrors.modelParentException(); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!(this._parent instanceof NgModelGroup) && + this._parent instanceof AbstractFormGroupDirective) { + TemplateDrivenErrors.formGroupNameException(); + } else if (!(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm)) { + TemplateDrivenErrors.modelParentException(); + } } } private _checkName(): void { if (this.options && this.options.name) this.name = this.options.name; - if (!this._isStandalone() && !this.name) { + if (!this._isStandalone() && !this.name && (typeof ngDevMode === 'undefined' || ngDevMode)) { TemplateDrivenErrors.missingNameException(); } } diff --git a/packages/forms/src/directives/ng_model_group.ts b/packages/forms/src/directives/ng_model_group.ts index d5995df8a7..7baabdf9cc 100644 --- a/packages/forms/src/directives/ng_model_group.ts +++ b/packages/forms/src/directives/ng_model_group.ts @@ -68,7 +68,8 @@ export class NgModelGroup extends AbstractFormGroupDirective implements OnInit, /** @internal */ _checkParentType(): void { - if (!(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm)) { + if (!(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm) && + (typeof ngDevMode === 'undefined' || ngDevMode)) { TemplateDrivenErrors.modelGroupParentException(); } } diff --git a/packages/forms/src/directives/radio_control_value_accessor.ts b/packages/forms/src/directives/radio_control_value_accessor.ts index 4de1274f2d..50fbee6e67 100644 --- a/packages/forms/src/directives/radio_control_value_accessor.ts +++ b/packages/forms/src/directives/radio_control_value_accessor.ts @@ -17,6 +17,13 @@ export const RADIO_VALUE_ACCESSOR: any = { multi: true }; +function throwNameError() { + throw new Error(` + If you define both a name and a formControlName attribute on your radio button, their values + must match. Ex: + `); +} + /** * @description * Class used by Angular to track radio buttons. For internal use only. @@ -213,16 +220,10 @@ export class RadioControlValueAccessor implements ControlValueAccessor, OnDestro } private _checkName(): void { - if (this.name && this.formControlName && this.name !== this.formControlName) { - this._throwNameError(); + if (this.name && this.formControlName && this.name !== this.formControlName && + (typeof ngDevMode === 'undefined' || ngDevMode)) { + throwNameError(); } if (!this.name && this.formControlName) this.name = this.formControlName; } - - private _throwNameError(): void { - throw new Error(` - If you define both a name and a formControlName attribute on your radio button, their values - must match. Ex: - `); - } } 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 2f288fbe3c..7d496aa99b 100644 --- a/packages/forms/src/directives/reactive_directives/form_control_directive.ts +++ b/packages/forms/src/directives/reactive_directives/form_control_directive.ts @@ -68,11 +68,13 @@ export class FormControlDirective extends NgControl implements OnChanges { /** * @description - * Triggers a warning that this input should not be used with reactive forms. + * Triggers a warning in dev mode that this input should not be used with reactive forms. */ @Input('disabled') set isDisabled(isDisabled: boolean) { - ReactiveErrors.disabledAttrWarning(); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + ReactiveErrors.disabledAttrWarning(); + } } // TODO(kara): remove next 4 properties once deprecation period is over 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 0802ff2b0e..34311c1886 100644 --- a/packages/forms/src/directives/reactive_directives/form_control_name.ts +++ b/packages/forms/src/directives/reactive_directives/form_control_name.ts @@ -92,11 +92,13 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy { /** * @description - * Triggers a warning that this input should not be used with reactive forms. + * Triggers a warning in dev mode that this input should not be used with reactive forms. */ @Input('disabled') set isDisabled(isDisabled: boolean) { - ReactiveErrors.disabledAttrWarning(); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + ReactiveErrors.disabledAttrWarning(); + } } // TODO(kara): remove next 4 properties once deprecation period is over @@ -212,13 +214,16 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy { } private _checkParentType(): void { - if (!(this._parent instanceof FormGroupName) && - this._parent instanceof AbstractFormGroupDirective) { - ReactiveErrors.ngModelGroupException(); - } else if ( - !(this._parent instanceof FormGroupName) && !(this._parent instanceof FormGroupDirective) && - !(this._parent instanceof FormArrayName)) { - ReactiveErrors.controlParentException(); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!(this._parent instanceof FormGroupName) && + this._parent instanceof AbstractFormGroupDirective) { + ReactiveErrors.ngModelGroupException(); + } else if ( + !(this._parent instanceof FormGroupName) && + !(this._parent instanceof FormGroupDirective) && + !(this._parent instanceof FormArrayName)) { + ReactiveErrors.controlParentException(); + } } } 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 f6ef709f55..3f864fc7c7 100644 --- a/packages/forms/src/directives/reactive_directives/form_group_directive.ts +++ b/packages/forms/src/directives/reactive_directives/form_group_directive.ts @@ -291,7 +291,7 @@ export class FormGroupDirective extends ControlContainer implements Form, OnChan } private _checkFormPresent() { - if (!this.form) { + if (!this.form && (typeof ngDevMode === 'undefined' || ngDevMode)) { ReactiveErrors.missingFormException(); } } 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 6a3aa99ba5..5cd1bf4ff6 100644 --- a/packages/forms/src/directives/reactive_directives/form_group_name.ts +++ b/packages/forms/src/directives/reactive_directives/form_group_name.ts @@ -96,7 +96,7 @@ export class FormGroupName extends AbstractFormGroupDirective implements OnInit, /** @internal */ _checkParentType(): void { - if (_hasInvalidParent(this._parent)) { + if (_hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) { ReactiveErrors.groupParentException(); } } @@ -228,7 +228,7 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy } private _checkParentType(): void { - if (_hasInvalidParent(this._parent)) { + if (_hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) { ReactiveErrors.arrayParentException(); } } diff --git a/packages/forms/src/directives/reactive_errors.ts b/packages/forms/src/directives/reactive_errors.ts index 835f358aa6..0d32b3e76e 100644 --- a/packages/forms/src/directives/reactive_errors.ts +++ b/packages/forms/src/directives/reactive_errors.ts @@ -33,6 +33,7 @@ export class ReactiveErrors { ${Examples.ngModelGroup}`); } + static missingFormException(): void { throw new Error(`formGroup expects a FormGroup instance. Please pass one in. diff --git a/packages/forms/src/directives/select_control_value_accessor.ts b/packages/forms/src/directives/select_control_value_accessor.ts index 4e2832c2a5..b333b0d0ca 100644 --- a/packages/forms/src/directives/select_control_value_accessor.ts +++ b/packages/forms/src/directives/select_control_value_accessor.ts @@ -115,7 +115,7 @@ export class SelectControlValueAccessor implements ControlValueAccessor { */ @Input() set compareWith(fn: (o1: any, o2: any) => boolean) { - if (typeof fn !== 'function') { + if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw new Error(`compareWith must be a function, but received ${JSON.stringify(fn)}`); } this._compareWith = fn; diff --git a/packages/forms/src/directives/select_multiple_control_value_accessor.ts b/packages/forms/src/directives/select_multiple_control_value_accessor.ts index ebee781504..2d6378fa04 100644 --- a/packages/forms/src/directives/select_multiple_control_value_accessor.ts +++ b/packages/forms/src/directives/select_multiple_control_value_accessor.ts @@ -112,7 +112,7 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor */ @Input() set compareWith(fn: (o1: any, o2: any) => boolean) { - if (typeof fn !== 'function') { + if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw new Error(`compareWith must be a function, but received ${JSON.stringify(fn)}`); } this._compareWith = fn; diff --git a/packages/forms/src/directives/shared.ts b/packages/forms/src/directives/shared.ts index 04c950aa9f..a3dcce5616 100644 --- a/packages/forms/src/directives/shared.ts +++ b/packages/forms/src/directives/shared.ts @@ -33,8 +33,10 @@ export function controlPath(name: string|null, parent: ControlContainer): string } export function setUpControl(control: FormControl, dir: NgControl): void { - if (!control) _throwError(dir, 'Cannot find control with'); - if (!dir.valueAccessor) _throwError(dir, 'No value accessor for form control with'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!control) _throwError(dir, 'Cannot find control with'); + if (!dir.valueAccessor) _throwError(dir, 'No value accessor for form control with'); + } control.validator = Validators.compose([control.validator!, dir.validator]); control.asyncValidator = Validators.composeAsync([control.asyncValidator!, dir.asyncValidator]); @@ -64,8 +66,14 @@ export function setUpControl(control: FormControl, dir: NgControl): void { } export function cleanUpControl(control: FormControl, dir: NgControl) { - dir.valueAccessor!.registerOnChange(() => _noControlError(dir)); - dir.valueAccessor!.registerOnTouched(() => _noControlError(dir)); + const noop = () => { + if (typeof ngDevMode === 'undefined' || ngDevMode) { + _noControlError(dir); + } + }; + + dir.valueAccessor!.registerOnChange(noop); + dir.valueAccessor!.registerOnTouched(noop); dir._rawValidators.forEach((validator: any) => { if (validator.registerOnValidatorChange) { @@ -120,7 +128,8 @@ function setUpModelChangePipeline(control: FormControl, dir: NgControl): void { export function setUpFormContainer( control: FormGroup|FormArray, dir: AbstractFormGroupDirective|FormArrayName) { - if (control == null) _throwError(dir, 'Cannot find control with'); + if (control == null && (typeof ngDevMode === 'undefined' || ngDevMode)) + _throwError(dir, 'Cannot find control with'); control.validator = Validators.compose([control.validator, dir.validator]); control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]); } @@ -190,7 +199,7 @@ export function selectValueAccessor( dir: NgControl, valueAccessors: ControlValueAccessor[]): ControlValueAccessor|null { if (!valueAccessors) return null; - if (!Array.isArray(valueAccessors)) + if (!Array.isArray(valueAccessors) && (typeof ngDevMode === 'undefined' || ngDevMode)) _throwError(dir, 'Value accessor was not provided as an array for form control with'); let defaultAccessor: ControlValueAccessor|undefined = undefined; @@ -202,12 +211,12 @@ export function selectValueAccessor( defaultAccessor = v; } else if (isBuiltInAccessor(v)) { - if (builtinAccessor) + if (builtinAccessor && (typeof ngDevMode === 'undefined' || ngDevMode)) _throwError(dir, 'More than one built-in value accessor matches form control with'); builtinAccessor = v; } else { - if (customAccessor) + if (customAccessor && (typeof ngDevMode === 'undefined' || ngDevMode)) _throwError(dir, 'More than one custom value accessor matches form control with'); customAccessor = v; } @@ -217,7 +226,9 @@ export function selectValueAccessor( if (builtinAccessor) return builtinAccessor; if (defaultAccessor) return defaultAccessor; - _throwError(dir, 'No valid value accessor for form control with'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + _throwError(dir, 'No valid value accessor for form control with'); + } return null; } @@ -234,7 +245,9 @@ export function _ngModelWarning( if (((warningConfig === null || warningConfig === 'once') && !type._ngModelWarningSentOnce) || (warningConfig === 'always' && !instance._ngModelWarningSent)) { - ReactiveErrors.ngModelWarning(name); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + ReactiveErrors.ngModelWarning(name); + } type._ngModelWarningSentOnce = true; instance._ngModelWarningSent = true; } diff --git a/packages/forms/src/validators.ts b/packages/forms/src/validators.ts index d2fb2bbf86..d45286a370 100644 --- a/packages/forms/src/validators.ts +++ b/packages/forms/src/validators.ts @@ -469,7 +469,7 @@ function isPresent(o: any): boolean { export function toObservable(r: any): Observable { const obs = isPromise(r) ? from(r) : r; - if (!(isObservable(obs))) { + if (!(isObservable(obs)) && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw new Error(`Expected validator to return Promise or Observable.`); } return obs;