style(forms): reformat of the forms
package after clang update (#36466)
PR Close #36466
This commit is contained in:

committed by
Kara Erickson

parent
416c786774
commit
7d0af179e3
@ -31,7 +31,9 @@ export abstract class AbstractControlDirective {
|
||||
* @description
|
||||
* Reports the value of the control if it is present, otherwise null.
|
||||
*/
|
||||
get value(): any { return this.control ? this.control.value : null; }
|
||||
get value(): any {
|
||||
return this.control ? this.control.value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -39,14 +41,18 @@ export abstract class AbstractControlDirective {
|
||||
* validation errors exist with the current value.
|
||||
* If the control is not present, null is returned.
|
||||
*/
|
||||
get valid(): boolean|null { return this.control ? this.control.valid : null; }
|
||||
get valid(): boolean|null {
|
||||
return this.control ? this.control.valid : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Reports whether the control is invalid, meaning that an error exists in the input value.
|
||||
* If the control is not present, null is returned.
|
||||
*/
|
||||
get invalid(): boolean|null { return this.control ? this.control.invalid : null; }
|
||||
get invalid(): boolean|null {
|
||||
return this.control ? this.control.invalid : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -54,7 +60,9 @@ export abstract class AbstractControlDirective {
|
||||
* errors are not yet available for the input value. If the control is not present, null is
|
||||
* returned.
|
||||
*/
|
||||
get pending(): boolean|null { return this.control ? this.control.pending : null; }
|
||||
get pending(): boolean|null {
|
||||
return this.control ? this.control.pending : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -62,41 +70,53 @@ export abstract class AbstractControlDirective {
|
||||
* in the UI and is exempt from validation checks and excluded from aggregate
|
||||
* values of ancestor controls. If the control is not present, null is returned.
|
||||
*/
|
||||
get disabled(): boolean|null { return this.control ? this.control.disabled : null; }
|
||||
get disabled(): boolean|null {
|
||||
return this.control ? this.control.disabled : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Reports whether the control is enabled, meaning that the control is included in ancestor
|
||||
* calculations of validity or value. If the control is not present, null is returned.
|
||||
*/
|
||||
get enabled(): boolean|null { return this.control ? this.control.enabled : null; }
|
||||
get enabled(): boolean|null {
|
||||
return this.control ? this.control.enabled : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Reports the control's validation errors. If the control is not present, null is returned.
|
||||
*/
|
||||
get errors(): ValidationErrors|null { return this.control ? this.control.errors : null; }
|
||||
get errors(): ValidationErrors|null {
|
||||
return this.control ? this.control.errors : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Reports whether the control is pristine, meaning that the user has not yet changed
|
||||
* the value in the UI. If the control is not present, null is returned.
|
||||
*/
|
||||
get pristine(): boolean|null { return this.control ? this.control.pristine : null; }
|
||||
get pristine(): boolean|null {
|
||||
return this.control ? this.control.pristine : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Reports whether the control is dirty, meaning that the user has changed
|
||||
* the value in the UI. If the control is not present, null is returned.
|
||||
*/
|
||||
get dirty(): boolean|null { return this.control ? this.control.dirty : null; }
|
||||
get dirty(): boolean|null {
|
||||
return this.control ? this.control.dirty : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Reports whether the control is touched, meaning that the user has triggered
|
||||
* a `blur` event on it. If the control is not present, null is returned.
|
||||
*/
|
||||
get touched(): boolean|null { return this.control ? this.control.touched : null; }
|
||||
get touched(): boolean|null {
|
||||
return this.control ? this.control.touched : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -104,14 +124,18 @@ export abstract class AbstractControlDirective {
|
||||
* 'VALID', 'INVALID', 'DISABLED', and 'PENDING'.
|
||||
* If the control is not present, null is returned.
|
||||
*/
|
||||
get status(): string|null { return this.control ? this.control.status : null; }
|
||||
get status(): string|null {
|
||||
return this.control ? this.control.status : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Reports whether the control is untouched, meaning that the user has not yet triggered
|
||||
* a `blur` event on it. If the control is not present, null is returned.
|
||||
*/
|
||||
get untouched(): boolean|null { return this.control ? this.control.untouched : null; }
|
||||
get untouched(): boolean|null {
|
||||
return this.control ? this.control.untouched : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -137,7 +161,9 @@ export abstract class AbstractControlDirective {
|
||||
* Returns an array that represents the path from the top-level form to this control.
|
||||
* Each index is the string name of the control on that level.
|
||||
*/
|
||||
get path(): string[]|null { return null; }
|
||||
get path(): string[]|null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
|
@ -31,7 +31,7 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn
|
||||
* @internal
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
_parent !: ControlContainer;
|
||||
_parent!: ControlContainer;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -40,7 +40,7 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn
|
||||
* @internal
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
_validators !: any[];
|
||||
_validators!: any[];
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -49,7 +49,7 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn
|
||||
* @internal
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
_asyncValidators !: any[];
|
||||
_asyncValidators!: any[];
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -58,7 +58,7 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this._checkParentType();
|
||||
this.formDirective !.addFormGroup(this);
|
||||
this.formDirective!.addFormGroup(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,7 +76,9 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn
|
||||
* @description
|
||||
* The `FormGroup` bound to this directive.
|
||||
*/
|
||||
get control(): FormGroup { return this.formDirective !.getFormGroup(this); }
|
||||
get control(): FormGroup {
|
||||
return this.formDirective!.getFormGroup(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -90,13 +92,17 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn
|
||||
* @description
|
||||
* The top-level directive for this group if present, otherwise null.
|
||||
*/
|
||||
get formDirective(): Form|null { return this._parent ? this._parent.formDirective : null; }
|
||||
get formDirective(): Form|null {
|
||||
return this._parent ? this._parent.formDirective : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* The synchronous validators registered with this group.
|
||||
*/
|
||||
get validator(): ValidatorFn|null { return composeValidators(this._validators); }
|
||||
get validator(): ValidatorFn|null {
|
||||
return composeValidators(this._validators);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, ElementRef, Renderer2, forwardRef} from '@angular/core';
|
||||
import {Directive, ElementRef, forwardRef, Renderer2} from '@angular/core';
|
||||
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
|
||||
|
||||
@ -75,7 +75,9 @@ export class CheckboxControlValueAccessor implements ControlValueAccessor {
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; }
|
||||
registerOnChange(fn: (_: any) => {}): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -83,7 +85,9 @@ export class CheckboxControlValueAccessor implements ControlValueAccessor {
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
|
||||
registerOnTouched(fn: () => {}): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "disabled" property on the input element.
|
||||
|
@ -23,17 +23,21 @@ export abstract class ControlContainer extends AbstractControlDirective {
|
||||
* The name for the control
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
name !: string | number | null;
|
||||
name!: string|number|null;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* The top-level form directive for the control.
|
||||
*/
|
||||
get formDirective(): Form|null { return null; }
|
||||
get formDirective(): Form|null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* The path to this group.
|
||||
*/
|
||||
get path(): string[]|null { return null; }
|
||||
get path(): string[]|null {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,8 @@
|
||||
*/
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {Directive, ElementRef, Inject, InjectionToken, Optional, Renderer2, forwardRef} from '@angular/core';
|
||||
import {Directive, ElementRef, forwardRef, Inject, InjectionToken, Optional, Renderer2} from '@angular/core';
|
||||
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
|
||||
|
||||
export const DEFAULT_VALUE_ACCESSOR: any = {
|
||||
@ -112,7 +113,9 @@ export class DefaultValueAccessor implements ControlValueAccessor {
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
|
||||
registerOnChange(fn: (_: any) => void): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -120,7 +123,9 @@ export class DefaultValueAccessor implements ControlValueAccessor {
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
|
||||
registerOnTouched(fn: () => void): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "disabled" property on the input element.
|
||||
@ -139,7 +144,9 @@ export class DefaultValueAccessor implements ControlValueAccessor {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_compositionStart(): void { this._composing = true; }
|
||||
_compositionStart(): void {
|
||||
this._composing = true;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_compositionEnd(value: any): void {
|
||||
|
@ -66,7 +66,9 @@ export abstract class NgControl extends AbstractControlDirective {
|
||||
*
|
||||
* @throws An exception that this method is not implemented
|
||||
*/
|
||||
get validator(): ValidatorFn|null { return <ValidatorFn>unimplemented(); }
|
||||
get validator(): ValidatorFn|null {
|
||||
return <ValidatorFn>unimplemented();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -74,7 +76,9 @@ export abstract class NgControl extends AbstractControlDirective {
|
||||
*
|
||||
* @throws An exception that this method is not implemented
|
||||
*/
|
||||
get asyncValidator(): AsyncValidatorFn|null { return <AsyncValidatorFn>unimplemented(); }
|
||||
get asyncValidator(): AsyncValidatorFn|null {
|
||||
return <AsyncValidatorFn>unimplemented();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
|
@ -15,15 +15,31 @@ import {NgControl} from './ng_control';
|
||||
export class AbstractControlStatus {
|
||||
private _cd: AbstractControlDirective;
|
||||
|
||||
constructor(cd: AbstractControlDirective) { this._cd = cd; }
|
||||
constructor(cd: AbstractControlDirective) {
|
||||
this._cd = cd;
|
||||
}
|
||||
|
||||
get ngClassUntouched(): boolean { return this._cd.control ? this._cd.control.untouched : false; }
|
||||
get ngClassTouched(): boolean { return this._cd.control ? this._cd.control.touched : false; }
|
||||
get ngClassPristine(): boolean { return this._cd.control ? this._cd.control.pristine : false; }
|
||||
get ngClassDirty(): boolean { return this._cd.control ? this._cd.control.dirty : false; }
|
||||
get ngClassValid(): boolean { return this._cd.control ? this._cd.control.valid : false; }
|
||||
get ngClassInvalid(): boolean { return this._cd.control ? this._cd.control.invalid : false; }
|
||||
get ngClassPending(): boolean { return this._cd.control ? this._cd.control.pending : false; }
|
||||
get ngClassUntouched(): boolean {
|
||||
return this._cd.control ? this._cd.control.untouched : false;
|
||||
}
|
||||
get ngClassTouched(): boolean {
|
||||
return this._cd.control ? this._cd.control.touched : false;
|
||||
}
|
||||
get ngClassPristine(): boolean {
|
||||
return this._cd.control ? this._cd.control.pristine : false;
|
||||
}
|
||||
get ngClassDirty(): boolean {
|
||||
return this._cd.control ? this._cd.control.dirty : false;
|
||||
}
|
||||
get ngClassValid(): boolean {
|
||||
return this._cd.control ? this._cd.control.valid : false;
|
||||
}
|
||||
get ngClassInvalid(): boolean {
|
||||
return this._cd.control ? this._cd.control.invalid : false;
|
||||
}
|
||||
get ngClassPending(): boolean {
|
||||
return this._cd.control ? this._cd.control.pending : false;
|
||||
}
|
||||
}
|
||||
|
||||
export const ngControlStatusHost = {
|
||||
@ -61,14 +77,16 @@ export const ngControlStatusHost = {
|
||||
*/
|
||||
@Directive({selector: '[formControlName],[ngModel],[formControl]', host: ngControlStatusHost})
|
||||
export class NgControlStatus extends AbstractControlStatus {
|
||||
constructor(@Self() cd: NgControl) { super(cd); }
|
||||
constructor(@Self() cd: NgControl) {
|
||||
super(cd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Directive automatically applied to Angular form groups that sets CSS classes
|
||||
* based on control status (valid/invalid/dirty/etc).
|
||||
*
|
||||
*
|
||||
* @see `NgControlStatus`
|
||||
*
|
||||
* @ngModule ReactiveFormsModule
|
||||
@ -81,5 +99,7 @@ export class NgControlStatus extends AbstractControlStatus {
|
||||
host: ngControlStatusHost
|
||||
})
|
||||
export class NgControlStatusGroup extends AbstractControlStatus {
|
||||
constructor(@Self() cd: ControlContainer) { super(cd); }
|
||||
constructor(@Self() cd: ControlContainer) {
|
||||
super(cd);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AfterViewInit, Directive, EventEmitter, Inject, Input, Optional, Self, forwardRef} from '@angular/core';
|
||||
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';
|
||||
@ -96,8 +96,7 @@ const resolvedPromise = (() => Promise.resolve(null))();
|
||||
outputs: ['ngSubmit'],
|
||||
exportAs: 'ngForm'
|
||||
})
|
||||
export class NgForm extends ControlContainer implements Form,
|
||||
AfterViewInit {
|
||||
export class NgForm extends ControlContainer implements Form, AfterViewInit {
|
||||
/**
|
||||
* @description
|
||||
* Returns whether the form submission has been triggered.
|
||||
@ -128,7 +127,7 @@ export class NgForm extends ControlContainer implements Form,
|
||||
*
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input('ngFormOptions') options !: {updateOn?: FormHooks};
|
||||
@Input('ngFormOptions') options!: {updateOn?: FormHooks};
|
||||
|
||||
constructor(
|
||||
@Optional() @Self() @Inject(NG_VALIDATORS) validators: any[],
|
||||
@ -142,32 +141,42 @@ export class NgForm extends ControlContainer implements Form,
|
||||
* @description
|
||||
* Lifecycle method called after the view is initialized. For internal use only.
|
||||
*/
|
||||
ngAfterViewInit() { this._setUpdateStrategy(); }
|
||||
ngAfterViewInit() {
|
||||
this._setUpdateStrategy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* The directive instance.
|
||||
*/
|
||||
get formDirective(): Form { return this; }
|
||||
get formDirective(): Form {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* The internal `FormGroup` instance.
|
||||
*/
|
||||
get control(): FormGroup { return this.form; }
|
||||
get control(): FormGroup {
|
||||
return this.form;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Returns an array representing the path to this group. Because this directive
|
||||
* always lives at the top level of a form, it is always an empty array.
|
||||
*/
|
||||
get path(): string[] { return []; }
|
||||
get path(): string[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Returns a map of the controls in this group.
|
||||
*/
|
||||
get controls(): {[key: string]: AbstractControl} { return this.form.controls; }
|
||||
get controls(): {[key: string]: AbstractControl} {
|
||||
return this.form.controls;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -179,7 +188,7 @@ export class NgForm extends ControlContainer implements Form,
|
||||
addControl(dir: NgModel): void {
|
||||
resolvedPromise.then(() => {
|
||||
const container = this._findContainer(dir.path);
|
||||
(dir as{control: FormControl}).control =
|
||||
(dir as {control: FormControl}).control =
|
||||
<FormControl>container.registerControl(dir.name, dir.control);
|
||||
setUpControl(dir.control, dir);
|
||||
dir.control.updateValueAndValidity({emitEvent: false});
|
||||
@ -193,7 +202,9 @@ export class NgForm extends ControlContainer implements Form,
|
||||
*
|
||||
* @param dir The `NgModel` directive instance.
|
||||
*/
|
||||
getControl(dir: NgModel): FormControl { return <FormControl>this.form.get(dir.path); }
|
||||
getControl(dir: NgModel): FormControl {
|
||||
return <FormControl>this.form.get(dir.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -248,7 +259,9 @@ export class NgForm extends ControlContainer implements Form,
|
||||
*
|
||||
* @param dir The `NgModelGroup` directive instance.
|
||||
*/
|
||||
getFormGroup(dir: NgModelGroup): FormGroup { return <FormGroup>this.form.get(dir.path); }
|
||||
getFormGroup(dir: NgModelGroup): FormGroup {
|
||||
return <FormGroup>this.form.get(dir.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new value for the provided `NgControl` directive.
|
||||
@ -258,7 +271,7 @@ export class NgForm extends ControlContainer implements Form,
|
||||
*/
|
||||
updateModel(dir: NgControl, value: any): void {
|
||||
resolvedPromise.then(() => {
|
||||
const ctrl = <FormControl>this.form.get(dir.path !);
|
||||
const ctrl = <FormControl>this.form.get(dir.path!);
|
||||
ctrl.setValue(value);
|
||||
});
|
||||
}
|
||||
@ -269,7 +282,9 @@ export class NgForm extends ControlContainer implements Form,
|
||||
*
|
||||
* @param value The new value
|
||||
*/
|
||||
setValue(value: {[key: string]: any}): void { this.control.setValue(value); }
|
||||
setValue(value: {[key: string]: any}): void {
|
||||
this.control.setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -279,7 +294,7 @@ export class NgForm extends ControlContainer implements Form,
|
||||
* @param $event The "submit" event object
|
||||
*/
|
||||
onSubmit($event: Event): boolean {
|
||||
(this as{submitted: boolean}).submitted = true;
|
||||
(this as {submitted: boolean}).submitted = true;
|
||||
syncPendingControls(this.form, this._directives);
|
||||
this.ngSubmit.emit($event);
|
||||
return false;
|
||||
@ -289,7 +304,9 @@ export class NgForm extends ControlContainer implements Form,
|
||||
* @description
|
||||
* Method called when the "reset" event is triggered on the form.
|
||||
*/
|
||||
onReset(): void { this.resetForm(); }
|
||||
onReset(): void {
|
||||
this.resetForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -299,7 +316,7 @@ export class NgForm extends ControlContainer implements Form,
|
||||
*/
|
||||
resetForm(value: any = undefined): void {
|
||||
this.form.reset(value);
|
||||
(this as{submitted: boolean}).submitted = false;
|
||||
(this as {submitted: boolean}).submitted = false;
|
||||
}
|
||||
|
||||
private _setUpdateStrategy() {
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, EventEmitter, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core';
|
||||
import {Directive, EventEmitter, forwardRef, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges} from '@angular/core';
|
||||
|
||||
import {FormControl, FormHooks} from '../model';
|
||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators';
|
||||
@ -64,17 +64,17 @@ const resolvedPromise = (() => Promise.resolve(null))();
|
||||
* (also known as 'banana-box syntax'), the value in the UI always syncs back to
|
||||
* the domain model in your class.
|
||||
*
|
||||
* To inspect the properties of the associated `FormControl` (like validity state),
|
||||
* export the directive into a local template variable using `ngModel` as the key (ex: `#myVar="ngModel"`).
|
||||
* You then access the control using the directive's `control` property,
|
||||
* but most properties used (like `valid` and `dirty`) fall through to the control anyway for direct access.
|
||||
* See a full list of properties directly available in `AbstractControlDirective`.
|
||||
* To inspect the properties of the associated `FormControl` (like validity state),
|
||||
* export the directive into a local template variable using `ngModel` as the key (ex:
|
||||
* `#myVar="ngModel"`). You then access the control using the directive's `control` property, but
|
||||
* most properties used (like `valid` and `dirty`) fall through to the control anyway for direct
|
||||
* access. See a full list of properties directly available in `AbstractControlDirective`.
|
||||
*
|
||||
* @see `RadioControlValueAccessor`
|
||||
* @see `RadioControlValueAccessor`
|
||||
* @see `SelectControlValueAccessor`
|
||||
*
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
*
|
||||
* ### Using ngModel on a standalone control
|
||||
*
|
||||
* The following examples show a simple standalone control using `ngModel`:
|
||||
@ -84,23 +84,23 @@ const resolvedPromise = (() => Promise.resolve(null))();
|
||||
* When using the `ngModel` within `<form>` tags, you'll also need to supply a `name` attribute
|
||||
* so that the control can be registered with the parent form under that name.
|
||||
*
|
||||
* In the context of a parent form, it's often unnecessary to include one-way or two-way binding,
|
||||
* as the parent form syncs the value for you. You access its properties by exporting it into a
|
||||
* local template variable using `ngForm` such as (`#f="ngForm"`). Use the variable where
|
||||
* In the context of a parent form, it's often unnecessary to include one-way or two-way binding,
|
||||
* as the parent form syncs the value for you. You access its properties by exporting it into a
|
||||
* local template variable using `ngForm` such as (`#f="ngForm"`). Use the variable where
|
||||
* needed on form submission.
|
||||
*
|
||||
* If you do need to populate initial values into your form, using a one-way binding for
|
||||
* `ngModel` tends to be sufficient as long as you use the exported form's value rather
|
||||
* than the domain model's value on submit.
|
||||
*
|
||||
*
|
||||
* ### Using ngModel within a form
|
||||
*
|
||||
* The following example shows controls using `ngModel` within a form:
|
||||
*
|
||||
* {@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
|
||||
*
|
||||
*
|
||||
* ### Using a standalone ngModel within a group
|
||||
*
|
||||
*
|
||||
* The following example shows you how to use a standalone ngModel control
|
||||
* within a form. This controls the display of the form, but doesn't contain form data.
|
||||
*
|
||||
@ -111,11 +111,11 @@ const resolvedPromise = (() => Promise.resolve(null))();
|
||||
* </form>
|
||||
* <!-- form value: {login: ''} -->
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* ### Setting the ngModel name attribute through options
|
||||
*
|
||||
* The following example shows you an alternate way to set the name attribute. The name attribute is used
|
||||
* within a custom form component, and the name `@Input` property serves a different purpose.
|
||||
*
|
||||
* The following example shows you an alternate way to set the name attribute. The name attribute is
|
||||
* used within a custom form component, and the name `@Input` property serves a different purpose.
|
||||
*
|
||||
* ```html
|
||||
* <form>
|
||||
@ -133,8 +133,7 @@ const resolvedPromise = (() => Promise.resolve(null))();
|
||||
providers: [formControlBinding],
|
||||
exportAs: 'ngModel'
|
||||
})
|
||||
export class NgModel extends NgControl implements OnChanges,
|
||||
OnDestroy {
|
||||
export class NgModel extends NgControl implements OnChanges, OnDestroy {
|
||||
public readonly control: FormControl = new FormControl();
|
||||
|
||||
// At runtime we coerce arbitrary values assigned to the "disabled" input to a "boolean".
|
||||
@ -161,14 +160,14 @@ export class NgModel extends NgControl implements OnChanges,
|
||||
* uses this name as a key to retrieve this control's value.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() name !: string;
|
||||
@Input() name!: string;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Tracks whether the control is disabled.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input('disabled') isDisabled !: boolean;
|
||||
@Input('disabled') isDisabled!: boolean;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -192,8 +191,7 @@ export class NgModel extends NgControl implements OnChanges,
|
||||
*
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input('ngModelOptions')
|
||||
options !: {name?: string, standalone?: boolean, updateOn?: FormHooks};
|
||||
@Input('ngModelOptions') options!: {name?: string, standalone?: boolean, updateOn?: FormHooks};
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -202,151 +200,156 @@ export class NgModel extends NgControl implements OnChanges,
|
||||
*/
|
||||
@Output('ngModelChange') update = new EventEmitter();
|
||||
|
||||
constructor(@Optional() @Host() parent: ControlContainer,
|
||||
@Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>,
|
||||
@Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<AsyncValidator|AsyncValidatorFn>,
|
||||
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR)
|
||||
valueAccessors: ControlValueAccessor[]) {
|
||||
super();
|
||||
this._parent = parent;
|
||||
this._rawValidators = validators || [];
|
||||
this._rawAsyncValidators = asyncValidators || [];
|
||||
this.valueAccessor = selectValueAccessor(this, valueAccessors);
|
||||
}
|
||||
constructor(
|
||||
@Optional() @Host() parent: ControlContainer,
|
||||
@Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>,
|
||||
@Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators:
|
||||
Array<AsyncValidator|AsyncValidatorFn>,
|
||||
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {
|
||||
super();
|
||||
this._parent = parent;
|
||||
this._rawValidators = validators || [];
|
||||
this._rawAsyncValidators = asyncValidators || [];
|
||||
this.valueAccessor = selectValueAccessor(this, valueAccessors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* A lifecycle method called when the directive's inputs change. For internal use
|
||||
* only.
|
||||
*
|
||||
* @param changes A object of key/value pairs for the set of changed inputs.
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
this._checkForErrors();
|
||||
if (!this._registered) this._setUpControl();
|
||||
if ('isDisabled' in changes) {
|
||||
this._updateDisabled(changes);
|
||||
}
|
||||
/**
|
||||
* @description
|
||||
* A lifecycle method called when the directive's inputs change. For internal use
|
||||
* only.
|
||||
*
|
||||
* @param changes A object of key/value pairs for the set of changed inputs.
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
this._checkForErrors();
|
||||
if (!this._registered) this._setUpControl();
|
||||
if ('isDisabled' in changes) {
|
||||
this._updateDisabled(changes);
|
||||
}
|
||||
|
||||
if (isPropertyUpdated(changes, this.viewModel)) {
|
||||
this._updateValue(this.model);
|
||||
this.viewModel = this.model;
|
||||
}
|
||||
}
|
||||
if (isPropertyUpdated(changes, this.viewModel)) {
|
||||
this._updateValue(this.model);
|
||||
this.viewModel = this.model;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Lifecycle method called before the directive's instance is destroyed. For internal
|
||||
* use only.
|
||||
*/
|
||||
ngOnDestroy(): void { this.formDirective && this.formDirective.removeControl(this); }
|
||||
/**
|
||||
* @description
|
||||
* Lifecycle method called before the directive's instance is destroyed. For internal
|
||||
* use only.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.formDirective && this.formDirective.removeControl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Returns an array that represents the path from the top-level form to this control.
|
||||
* Each index is the string name of the control on that level.
|
||||
*/
|
||||
get path(): string[] {
|
||||
return this._parent ? controlPath(this.name, this._parent) : [this.name];
|
||||
}
|
||||
/**
|
||||
* @description
|
||||
* Returns an array that represents the path from the top-level form to this control.
|
||||
* Each index is the string name of the control on that level.
|
||||
*/
|
||||
get path(): string[] {
|
||||
return this._parent ? controlPath(this.name, this._parent) : [this.name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* The top-level directive for this control if present, otherwise null.
|
||||
*/
|
||||
get formDirective(): any { return this._parent ? this._parent.formDirective : null; }
|
||||
/**
|
||||
* @description
|
||||
* The top-level directive for this control if present, otherwise null.
|
||||
*/
|
||||
get formDirective(): any {
|
||||
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
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* @param newValue The new value emitted by `ngModelChange`.
|
||||
*/
|
||||
viewToModelUpdate(newValue: any): void {
|
||||
this.viewModel = newValue;
|
||||
this.update.emit(newValue);
|
||||
}
|
||||
/**
|
||||
* @description
|
||||
* Sets the new value for the view model and emits an `ngModelChange` event.
|
||||
*
|
||||
* @param newValue The new value emitted by `ngModelChange`.
|
||||
*/
|
||||
viewToModelUpdate(newValue: any): void {
|
||||
this.viewModel = newValue;
|
||||
this.update.emit(newValue);
|
||||
}
|
||||
|
||||
private _setUpControl(): void {
|
||||
this._setUpdateStrategy();
|
||||
this._isStandalone() ? this._setUpStandalone() :
|
||||
this.formDirective.addControl(this);
|
||||
this._registered = true;
|
||||
}
|
||||
private _setUpControl(): void {
|
||||
this._setUpdateStrategy();
|
||||
this._isStandalone() ? this._setUpStandalone() : this.formDirective.addControl(this);
|
||||
this._registered = true;
|
||||
}
|
||||
|
||||
private _setUpdateStrategy(): void {
|
||||
if (this.options && this.options.updateOn != null) {
|
||||
this.control._updateOn = this.options.updateOn;
|
||||
}
|
||||
}
|
||||
private _setUpdateStrategy(): void {
|
||||
if (this.options && this.options.updateOn != null) {
|
||||
this.control._updateOn = this.options.updateOn;
|
||||
}
|
||||
}
|
||||
|
||||
private _isStandalone(): boolean {
|
||||
return !this._parent || !!(this.options && this.options.standalone);
|
||||
}
|
||||
private _isStandalone(): boolean {
|
||||
return !this._parent || !!(this.options && this.options.standalone);
|
||||
}
|
||||
|
||||
private _setUpStandalone(): void {
|
||||
setUpControl(this.control, this);
|
||||
this.control.updateValueAndValidity({emitEvent: false});
|
||||
}
|
||||
private _setUpStandalone(): void {
|
||||
setUpControl(this.control, this);
|
||||
this.control.updateValueAndValidity({emitEvent: false});
|
||||
}
|
||||
|
||||
private _checkForErrors(): void {
|
||||
if (!this._isStandalone()) {
|
||||
this._checkParentType();
|
||||
}
|
||||
this._checkName();
|
||||
}
|
||||
private _checkForErrors(): void {
|
||||
if (!this._isStandalone()) {
|
||||
this._checkParentType();
|
||||
}
|
||||
this._checkName();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private _checkName(): void {
|
||||
if (this.options && this.options.name) this.name = this.options.name;
|
||||
private _checkName(): void {
|
||||
if (this.options && this.options.name) this.name = this.options.name;
|
||||
|
||||
if (!this._isStandalone() && !this.name) {
|
||||
TemplateDrivenErrors.missingNameException();
|
||||
}
|
||||
}
|
||||
if (!this._isStandalone() && !this.name) {
|
||||
TemplateDrivenErrors.missingNameException();
|
||||
}
|
||||
}
|
||||
|
||||
private _updateValue(value: any): void {
|
||||
resolvedPromise.then(
|
||||
() => { this.control.setValue(value, {emitViewToModelChange: false}); });
|
||||
}
|
||||
private _updateValue(value: any): void {
|
||||
resolvedPromise.then(() => {
|
||||
this.control.setValue(value, {emitViewToModelChange: false});
|
||||
});
|
||||
}
|
||||
|
||||
private _updateDisabled(changes: SimpleChanges) {
|
||||
const disabledValue = changes['isDisabled'].currentValue;
|
||||
private _updateDisabled(changes: SimpleChanges) {
|
||||
const disabledValue = changes['isDisabled'].currentValue;
|
||||
|
||||
const isDisabled =
|
||||
disabledValue === '' || (disabledValue && disabledValue !== 'false');
|
||||
const isDisabled = disabledValue === '' || (disabledValue && disabledValue !== 'false');
|
||||
|
||||
resolvedPromise.then(() => {
|
||||
if (isDisabled && !this.control.disabled) {
|
||||
this.control.disable();
|
||||
} else if (!isDisabled && this.control.disabled) {
|
||||
this.control.enable();
|
||||
}
|
||||
});
|
||||
}
|
||||
resolvedPromise.then(() => {
|
||||
if (isDisabled && !this.control.disabled) {
|
||||
this.control.disable();
|
||||
} else if (!isDisabled && this.control.disabled) {
|
||||
this.control.enable();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf, forwardRef} from '@angular/core';
|
||||
import {Directive, forwardRef, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf} from '@angular/core';
|
||||
|
||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators';
|
||||
|
||||
@ -54,7 +54,7 @@ export class NgModelGroup extends AbstractFormGroupDirective implements OnInit,
|
||||
* to a key in the parent `NgForm`.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input('ngModelGroup') name !: string;
|
||||
@Input('ngModelGroup') name!: string;
|
||||
|
||||
constructor(
|
||||
@Host() @SkipSelf() parent: ControlContainer,
|
||||
|
@ -9,7 +9,7 @@
|
||||
import {AbstractControl} from '../model';
|
||||
import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators';
|
||||
|
||||
export function normalizeValidator(validator: ValidatorFn | Validator): ValidatorFn {
|
||||
export function normalizeValidator(validator: ValidatorFn|Validator): ValidatorFn {
|
||||
if ((<Validator>validator).validate) {
|
||||
return (c: AbstractControl) => (<Validator>validator).validate(c);
|
||||
} else {
|
||||
@ -17,8 +17,8 @@ export function normalizeValidator(validator: ValidatorFn | Validator): Validato
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeAsyncValidator(validator: AsyncValidatorFn | AsyncValidator):
|
||||
AsyncValidatorFn {
|
||||
export function normalizeAsyncValidator(validator: AsyncValidatorFn|
|
||||
AsyncValidator): AsyncValidatorFn {
|
||||
if ((<AsyncValidator>validator).validate) {
|
||||
return (c: AbstractControl) => (<AsyncValidator>validator).validate(c);
|
||||
} else {
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, ElementRef, Renderer2, forwardRef} from '@angular/core';
|
||||
import {Directive, ElementRef, forwardRef, Renderer2} from '@angular/core';
|
||||
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
|
||||
|
||||
@ -84,7 +84,9 @@ export class NumberValueAccessor implements ControlValueAccessor {
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnChange(fn: (_: number|null) => void): void {
|
||||
this.onChange = (value) => { fn(value == '' ? null : parseFloat(value)); };
|
||||
this.onChange = (value) => {
|
||||
fn(value == '' ? null : parseFloat(value));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,7 +95,9 @@ export class NumberValueAccessor implements ControlValueAccessor {
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
|
||||
registerOnTouched(fn: () => void): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "disabled" property on the input element.
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, ElementRef, Injectable, Injector, Input, OnDestroy, OnInit, Renderer2, forwardRef} from '@angular/core';
|
||||
import {Directive, ElementRef, forwardRef, Injectable, Injector, Input, OnDestroy, OnInit, Renderer2} from '@angular/core';
|
||||
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
|
||||
import {NgControl} from './ng_control';
|
||||
@ -93,17 +93,16 @@ export class RadioControlRegistry {
|
||||
host: {'(change)': 'onChange()', '(blur)': 'onTouched()'},
|
||||
providers: [RADIO_VALUE_ACCESSOR]
|
||||
})
|
||||
export class RadioControlValueAccessor implements ControlValueAccessor,
|
||||
OnDestroy, OnInit {
|
||||
export class RadioControlValueAccessor implements ControlValueAccessor, OnDestroy, OnInit {
|
||||
/** @internal */
|
||||
// TODO(issue/24571): remove '!'.
|
||||
_state !: boolean;
|
||||
_state!: boolean;
|
||||
/** @internal */
|
||||
// TODO(issue/24571): remove '!'.
|
||||
_control !: NgControl;
|
||||
_control!: NgControl;
|
||||
/** @internal */
|
||||
// TODO(issue/24571): remove '!'.
|
||||
_fn !: Function;
|
||||
_fn!: Function;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -122,7 +121,7 @@ export class RadioControlValueAccessor implements ControlValueAccessor,
|
||||
* Tracks the name of the radio input element.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() name !: string;
|
||||
@Input() name!: string;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -130,7 +129,7 @@ export class RadioControlValueAccessor implements ControlValueAccessor,
|
||||
* to a key in the parent `FormGroup` or `FormArray`.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() formControlName !: string;
|
||||
@Input() formControlName!: string;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -156,7 +155,9 @@ export class RadioControlValueAccessor implements ControlValueAccessor,
|
||||
* @description
|
||||
* Lifecycle method called before the directive's instance is destroyed. For internal use only.
|
||||
*/
|
||||
ngOnDestroy(): void { this._registry.remove(this); }
|
||||
ngOnDestroy(): void {
|
||||
this._registry.remove(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -188,7 +189,9 @@ export class RadioControlValueAccessor implements ControlValueAccessor,
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
fireUncheck(value: any): void { this.writeValue(value); }
|
||||
fireUncheck(value: any): void {
|
||||
this.writeValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -196,7 +199,9 @@ export class RadioControlValueAccessor implements ControlValueAccessor,
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
|
||||
registerOnTouched(fn: () => {}): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "disabled" property on the input element.
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, ElementRef, Renderer2, StaticProvider, forwardRef} from '@angular/core';
|
||||
import {Directive, ElementRef, forwardRef, Renderer2, StaticProvider} from '@angular/core';
|
||||
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
|
||||
|
||||
@ -82,7 +82,9 @@ export class RangeValueAccessor implements ControlValueAccessor {
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnChange(fn: (_: number|null) => void): void {
|
||||
this.onChange = (value) => { fn(value == '' ? null : parseFloat(value)); };
|
||||
this.onChange = (value) => {
|
||||
fn(value == '' ? null : parseFloat(value));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,7 +93,9 @@ export class RangeValueAccessor implements ControlValueAccessor {
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
|
||||
registerOnTouched(fn: () => void): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "disabled" property on the range input element.
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, EventEmitter, Inject, InjectionToken, Input, OnChanges, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core';
|
||||
import {Directive, EventEmitter, forwardRef, Inject, InjectionToken, Input, OnChanges, Optional, Output, Self, SimpleChanges} from '@angular/core';
|
||||
|
||||
import {FormControl} from '../../model';
|
||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators';
|
||||
@ -31,7 +31,7 @@ export const formControlBinding: any = {
|
||||
/**
|
||||
* @description
|
||||
* * Syncs a standalone `FormControl` instance to a form control element.
|
||||
*
|
||||
*
|
||||
* @see [Reactive Forms Guide](guide/reactive-forms)
|
||||
* @see `FormControl`
|
||||
* @see `AbstractControl`
|
||||
@ -39,7 +39,7 @@ export const formControlBinding: any = {
|
||||
* @usageNotes
|
||||
*
|
||||
* ### Registering a single form control
|
||||
*
|
||||
*
|
||||
* The following examples shows how to register a standalone control and set its value.
|
||||
*
|
||||
* {@example forms/ts/simpleFormControl/simple_form_control_example.ts region='Component'}
|
||||
@ -129,14 +129,16 @@ export class FormControlDirective extends NgControl implements OnChanges {
|
||||
* Tracks the `FormControl` instance bound to the directive.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input('formControl') form !: FormControl;
|
||||
@Input('formControl') form!: FormControl;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Triggers a warning that this input should not be used with reactive forms.
|
||||
*/
|
||||
@Input('disabled')
|
||||
set isDisabled(isDisabled: boolean) { ReactiveErrors.disabledAttrWarning(); }
|
||||
set isDisabled(isDisabled: boolean) {
|
||||
ReactiveErrors.disabledAttrWarning();
|
||||
}
|
||||
|
||||
// TODO(kara): remove next 4 properties once deprecation period is over
|
||||
|
||||
@ -164,81 +166,88 @@ export class FormControlDirective extends NgControl implements OnChanges {
|
||||
*/
|
||||
_ngModelWarningSent = false;
|
||||
|
||||
constructor(@Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>,
|
||||
@Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<AsyncValidator|AsyncValidatorFn>,
|
||||
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR)
|
||||
valueAccessors: ControlValueAccessor[],
|
||||
@Optional() @Inject(NG_MODEL_WITH_FORM_CONTROL_WARNING) private _ngModelWarningConfig: string|null) {
|
||||
super();
|
||||
this._rawValidators = validators || [];
|
||||
this._rawAsyncValidators = asyncValidators || [];
|
||||
this.valueAccessor = selectValueAccessor(this, valueAccessors);
|
||||
}
|
||||
constructor(
|
||||
@Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>,
|
||||
@Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators:
|
||||
Array<AsyncValidator|AsyncValidatorFn>,
|
||||
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[],
|
||||
@Optional() @Inject(NG_MODEL_WITH_FORM_CONTROL_WARNING) private _ngModelWarningConfig: string|
|
||||
null) {
|
||||
super();
|
||||
this._rawValidators = validators || [];
|
||||
this._rawAsyncValidators = asyncValidators || [];
|
||||
this.valueAccessor = selectValueAccessor(this, valueAccessors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* A lifecycle method called when the directive's inputs change. For internal use
|
||||
* only.
|
||||
*
|
||||
* @param changes A object of key/value pairs for the set of changed inputs.
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (this._isControlChanged(changes)) {
|
||||
setUpControl(this.form, this);
|
||||
if (this.control.disabled && this.valueAccessor !.setDisabledState) {
|
||||
this.valueAccessor !.setDisabledState !(true);
|
||||
}
|
||||
this.form.updateValueAndValidity({emitEvent: false});
|
||||
}
|
||||
if (isPropertyUpdated(changes, this.viewModel)) {
|
||||
_ngModelWarning(
|
||||
'formControl', FormControlDirective, this, this._ngModelWarningConfig);
|
||||
this.form.setValue(this.model);
|
||||
this.viewModel = this.model;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @description
|
||||
* A lifecycle method called when the directive's inputs change. For internal use
|
||||
* only.
|
||||
*
|
||||
* @param changes A object of key/value pairs for the set of changed inputs.
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (this._isControlChanged(changes)) {
|
||||
setUpControl(this.form, this);
|
||||
if (this.control.disabled && this.valueAccessor!.setDisabledState) {
|
||||
this.valueAccessor!.setDisabledState!(true);
|
||||
}
|
||||
this.form.updateValueAndValidity({emitEvent: false});
|
||||
}
|
||||
if (isPropertyUpdated(changes, this.viewModel)) {
|
||||
_ngModelWarning('formControl', FormControlDirective, this, this._ngModelWarningConfig);
|
||||
this.form.setValue(this.model);
|
||||
this.viewModel = this.model;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Returns an array that represents the path from the top-level form to this control.
|
||||
* Each index is the string name of the control on that level.
|
||||
*/
|
||||
get path(): string[] { return []; }
|
||||
/**
|
||||
* @description
|
||||
* Returns an array that represents the path from the top-level form to this control.
|
||||
* Each index is the string name of the control on that level.
|
||||
*/
|
||||
get path(): string[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Synchronous validator function composed of all the synchronous validators
|
||||
* registered with this directive.
|
||||
*/
|
||||
get validator(): ValidatorFn|null { return composeValidators(this._rawValidators); }
|
||||
/**
|
||||
* @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
|
||||
* 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.
|
||||
*/
|
||||
get control(): FormControl { return this.form; }
|
||||
/**
|
||||
* @description
|
||||
* The `FormControl` bound to this directive.
|
||||
*/
|
||||
get control(): FormControl {
|
||||
return this.form;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Sets the new value for the view model and emits an `ngModelChange` event.
|
||||
*
|
||||
* @param newValue The new value for the view model.
|
||||
*/
|
||||
viewToModelUpdate(newValue: any): void {
|
||||
this.viewModel = newValue;
|
||||
this.update.emit(newValue);
|
||||
}
|
||||
/**
|
||||
* @description
|
||||
* Sets the new value for the view model and emits an `ngModelChange` event.
|
||||
*
|
||||
* @param newValue The new value for the view model.
|
||||
*/
|
||||
viewToModelUpdate(newValue: any): void {
|
||||
this.viewModel = newValue;
|
||||
this.update.emit(newValue);
|
||||
}
|
||||
|
||||
private _isControlChanged(changes: {[key: string]: any}): boolean {
|
||||
return changes.hasOwnProperty('form');
|
||||
}
|
||||
private _isControlChanged(changes: {[key: string]: any}): boolean {
|
||||
return changes.hasOwnProperty('form');
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, EventEmitter, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, SkipSelf, forwardRef} from '@angular/core';
|
||||
import {Directive, EventEmitter, forwardRef, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, SkipSelf} from '@angular/core';
|
||||
|
||||
import {FormControl} from '../../model';
|
||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators';
|
||||
@ -31,13 +31,13 @@ export const controlNameBinding: any = {
|
||||
* @description
|
||||
* Syncs a `FormControl` in an existing `FormGroup` to a form control
|
||||
* element by name.
|
||||
*
|
||||
*
|
||||
* @see [Reactive Forms Guide](guide/reactive-forms)
|
||||
* @see `FormControl`
|
||||
* @see `AbstractControl`
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
*
|
||||
* ### Register `FormControl` within a group
|
||||
*
|
||||
* The following example shows how to register multiple form controls within a form group
|
||||
@ -140,7 +140,7 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
|
||||
* Tracks the `FormControl` instance bound to the directive.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
readonly control !: FormControl;
|
||||
readonly control!: FormControl;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -152,14 +152,16 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
|
||||
* to indices when iterating over controls in a `FormArray`.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input('formControlName') name !: string | number | null;
|
||||
@Input('formControlName') name!: string|number|null;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Triggers a warning that this input should not be used with reactive forms.
|
||||
*/
|
||||
@Input('disabled')
|
||||
set isDisabled(isDisabled: boolean) { ReactiveErrors.disabledAttrWarning(); }
|
||||
set isDisabled(isDisabled: boolean) {
|
||||
ReactiveErrors.disabledAttrWarning();
|
||||
}
|
||||
|
||||
// TODO(kara): remove next 4 properties once deprecation period is over
|
||||
|
||||
@ -244,21 +246,25 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
|
||||
* Each index is the string name of the control on that level.
|
||||
*/
|
||||
get path(): string[] {
|
||||
return controlPath(this.name == null ? this.name : this.name.toString(), this._parent !);
|
||||
return controlPath(this.name == null ? this.name : this.name.toString(), this._parent!);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* The top-level directive for this group if present, otherwise null.
|
||||
*/
|
||||
get formDirective(): any { return this._parent ? this._parent.formDirective : null; }
|
||||
get formDirective(): any {
|
||||
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); }
|
||||
get validator(): ValidatorFn|null {
|
||||
return composeValidators(this._rawValidators);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -266,7 +272,7 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
|
||||
* directive.
|
||||
*/
|
||||
get asyncValidator(): AsyncValidatorFn {
|
||||
return composeAsyncValidators(this._rawAsyncValidators) !;
|
||||
return composeAsyncValidators(this._rawAsyncValidators)!;
|
||||
}
|
||||
|
||||
private _checkParentType(): void {
|
||||
@ -282,9 +288,9 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
|
||||
|
||||
private _setUpControl() {
|
||||
this._checkParentType();
|
||||
(this as{control: FormControl}).control = this.formDirective.addControl(this);
|
||||
if (this.control.disabled && this.valueAccessor !.setDisabledState) {
|
||||
this.valueAccessor !.setDisabledState !(true);
|
||||
(this as {control: FormControl}).control = this.formDirective.addControl(this);
|
||||
if (this.control.disabled && this.valueAccessor!.setDisabledState) {
|
||||
this.valueAccessor!.setDisabledState!(true);
|
||||
}
|
||||
this._added = true;
|
||||
}
|
||||
|
@ -6,7 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, EventEmitter, Inject, Input, OnChanges, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core';
|
||||
import {Directive, EventEmitter, forwardRef, Inject, Input, OnChanges, Optional, Output, Self, SimpleChanges} from '@angular/core';
|
||||
|
||||
import {FormArray, FormControl, FormGroup} from '../../model';
|
||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from '../../validators';
|
||||
import {ControlContainer} from '../control_container';
|
||||
@ -31,7 +32,7 @@ export const formDirectiveProvider: any = {
|
||||
* `FormGroup` instance to match any child `FormControl`, `FormGroup`,
|
||||
* and `FormArray` instances to child `FormControlName`, `FormGroupName`,
|
||||
* and `FormArrayName` directives.
|
||||
*
|
||||
*
|
||||
* @see [Reactive Forms Guide](guide/reactive-forms)
|
||||
* @see `AbstractControl`
|
||||
*
|
||||
@ -51,8 +52,7 @@ export const formDirectiveProvider: any = {
|
||||
host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'},
|
||||
exportAs: 'ngForm'
|
||||
})
|
||||
export class FormGroupDirective extends ControlContainer implements Form,
|
||||
OnChanges {
|
||||
export class FormGroupDirective extends ControlContainer implements Form, OnChanges {
|
||||
/**
|
||||
* @description
|
||||
* Reports whether the form submission has been triggered.
|
||||
@ -60,7 +60,7 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
public readonly submitted: boolean = false;
|
||||
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _oldForm !: FormGroup;
|
||||
private _oldForm!: FormGroup;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -72,7 +72,7 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
* @description
|
||||
* Tracks the `FormGroup` bound to this directive.
|
||||
*/
|
||||
@Input('formGroup') form: FormGroup = null !;
|
||||
@Input('formGroup') form: FormGroup = null!;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -105,20 +105,26 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
* @description
|
||||
* Returns this directive's instance.
|
||||
*/
|
||||
get formDirective(): Form { return this; }
|
||||
get formDirective(): Form {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Returns the `FormGroup` bound to this directive.
|
||||
*/
|
||||
get control(): FormGroup { return this.form; }
|
||||
get control(): FormGroup {
|
||||
return this.form;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Returns an array representing the path to this group. Because this directive
|
||||
* always lives at the top level of a form, it always an empty array.
|
||||
*/
|
||||
get path(): string[] { return []; }
|
||||
get path(): string[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -141,7 +147,9 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
*
|
||||
* @param dir The `FormControlName` directive instance.
|
||||
*/
|
||||
getControl(dir: FormControlName): FormControl { return <FormControl>this.form.get(dir.path); }
|
||||
getControl(dir: FormControlName): FormControl {
|
||||
return <FormControl>this.form.get(dir.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -149,7 +157,9 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
*
|
||||
* @param dir The `FormControlName` directive instance.
|
||||
*/
|
||||
removeControl(dir: FormControlName): void { removeDir<FormControlName>(this.directives, dir); }
|
||||
removeControl(dir: FormControlName): void {
|
||||
removeDir<FormControlName>(this.directives, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new `FormGroupName` directive instance to the form.
|
||||
@ -175,7 +185,9 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
*
|
||||
* @param dir The `FormGroupName` directive instance.
|
||||
*/
|
||||
getFormGroup(dir: FormGroupName): FormGroup { return <FormGroup>this.form.get(dir.path); }
|
||||
getFormGroup(dir: FormGroupName): FormGroup {
|
||||
return <FormGroup>this.form.get(dir.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new `FormArrayName` directive instance to the form.
|
||||
@ -201,7 +213,9 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
*
|
||||
* @param dir The `FormArrayName` directive instance.
|
||||
*/
|
||||
getFormArray(dir: FormArrayName): FormArray { return <FormArray>this.form.get(dir.path); }
|
||||
getFormArray(dir: FormArrayName): FormArray {
|
||||
return <FormArray>this.form.get(dir.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new value for the provided `FormControlName` directive.
|
||||
@ -222,7 +236,7 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
* @param $event The "submit" event object
|
||||
*/
|
||||
onSubmit($event: Event): boolean {
|
||||
(this as{submitted: boolean}).submitted = true;
|
||||
(this as {submitted: boolean}).submitted = true;
|
||||
syncPendingControls(this.form, this.directives);
|
||||
this.ngSubmit.emit($event);
|
||||
return false;
|
||||
@ -232,7 +246,9 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
* @description
|
||||
* Method called when the "reset" event is triggered on the form.
|
||||
*/
|
||||
onReset(): void { this.resetForm(); }
|
||||
onReset(): void {
|
||||
this.resetForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -242,7 +258,7 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
*/
|
||||
resetForm(value: any = undefined): void {
|
||||
this.form.reset(value);
|
||||
(this as{submitted: boolean}).submitted = false;
|
||||
(this as {submitted: boolean}).submitted = false;
|
||||
}
|
||||
|
||||
|
||||
@ -253,7 +269,7 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
if (dir.control !== newCtrl) {
|
||||
cleanUpControl(dir.control, dir);
|
||||
if (newCtrl) setUpControl(newCtrl, dir);
|
||||
(dir as{control: FormControl}).control = newCtrl;
|
||||
(dir as {control: FormControl}).control = newCtrl;
|
||||
}
|
||||
});
|
||||
|
||||
@ -268,10 +284,10 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||
|
||||
private _updateValidators() {
|
||||
const sync = composeValidators(this._validators);
|
||||
this.form.validator = Validators.compose([this.form.validator !, sync !]);
|
||||
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.asyncValidator = Validators.composeAsync([this.form.asyncValidator!, async!]);
|
||||
}
|
||||
|
||||
private _checkFormPresent() {
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf, forwardRef} from '@angular/core';
|
||||
import {Directive, forwardRef, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf} from '@angular/core';
|
||||
|
||||
import {FormArray} from '../../model';
|
||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators';
|
||||
@ -82,7 +82,7 @@ export class FormGroupName extends AbstractFormGroupDirective implements OnInit,
|
||||
* to indices when iterating over groups in a `FormArray`.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input('formGroupName') name !: string | number | null;
|
||||
@Input('formGroupName') name!: string|number|null;
|
||||
|
||||
constructor(
|
||||
@Optional() @Host() @SkipSelf() parent: ControlContainer,
|
||||
@ -152,7 +152,7 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy
|
||||
* to indices when iterating over arrays in a `FormArray`.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input('formArrayName') name !: string | number | null;
|
||||
@Input('formArrayName') name!: string|number|null;
|
||||
|
||||
constructor(
|
||||
@Optional() @Host() @SkipSelf() parent: ControlContainer,
|
||||
@ -172,7 +172,7 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this._checkParentType();
|
||||
this.formDirective !.addFormArray(this);
|
||||
this.formDirective!.addFormArray(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,7 +189,9 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy
|
||||
* @description
|
||||
* The `FormArray` bound to this directive.
|
||||
*/
|
||||
get control(): FormArray { return this.formDirective !.getFormArray(this); }
|
||||
get control(): FormArray {
|
||||
return this.formDirective!.getFormArray(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -213,7 +215,9 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy
|
||||
* Synchronous validator function composed of all the synchronous validators registered with this
|
||||
* directive.
|
||||
*/
|
||||
get validator(): ValidatorFn|null { return composeValidators(this._validators); }
|
||||
get validator(): ValidatorFn|null {
|
||||
return composeValidators(this._validators);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
|
@ -83,8 +83,9 @@ export class ReactiveErrors {
|
||||
in Angular v7.
|
||||
|
||||
For more information on this, see our API docs here:
|
||||
https://angular.io/api/forms/${directiveName === 'formControl' ? 'FormControlDirective'
|
||||
: 'FormControlName'}#use-with-ngmodel
|
||||
https://angular.io/api/forms/${
|
||||
directiveName === 'formControl' ? 'FormControlDirective' :
|
||||
'FormControlName'}#use-with-ngmodel
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, ElementRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, forwardRef, ɵlooseIdentical as looseIdentical} from '@angular/core';
|
||||
import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, ɵlooseIdentical as looseIdentical} from '@angular/core';
|
||||
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
|
||||
|
||||
@ -16,7 +16,7 @@ export const SELECT_VALUE_ACCESSOR: StaticProvider = {
|
||||
multi: true
|
||||
};
|
||||
|
||||
function _buildValueString(id: string | null, value: any): string {
|
||||
function _buildValueString(id: string|null, value: any): string {
|
||||
if (id == null) return `${value}`;
|
||||
if (value && typeof value === 'object') value = 'Object';
|
||||
return `${id}: ${value}`.slice(0, 50);
|
||||
@ -160,7 +160,9 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnTouched(fn: () => any): void { this.onTouched = fn; }
|
||||
registerOnTouched(fn: () => any): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "disabled" property on the select input element.
|
||||
@ -172,7 +174,9 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_registerOption(): string { return (this._idCounter++).toString(); }
|
||||
_registerOption(): string {
|
||||
return (this._idCounter++).toString();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_getOptionId(value: any): string|null {
|
||||
@ -206,7 +210,7 @@ export class NgSelectOption implements OnDestroy {
|
||||
* ID of the option element
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
id !: string;
|
||||
id!: string;
|
||||
|
||||
constructor(
|
||||
private _element: ElementRef, private _renderer: Renderer2,
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, ElementRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, forwardRef, ɵlooseIdentical as looseIdentical} from '@angular/core';
|
||||
import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, ɵlooseIdentical as looseIdentical} from '@angular/core';
|
||||
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
|
||||
|
||||
@ -36,24 +36,24 @@ interface HTMLOption {
|
||||
/** Mock interface for HTMLCollection */
|
||||
abstract class HTMLCollection {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
length !: number;
|
||||
length!: number;
|
||||
abstract item(_: number): HTMLOption;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* The `ControlValueAccessor` for writing multi-select control values and listening to multi-select control
|
||||
* changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
|
||||
* directives.
|
||||
*
|
||||
* The `ControlValueAccessor` for writing multi-select control values and listening to multi-select
|
||||
* control changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
|
||||
* `NgModel` directives.
|
||||
*
|
||||
* @see `SelectControlValueAccessor`
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
*
|
||||
* ### Using a multi-select control
|
||||
*
|
||||
*
|
||||
* The follow example shows you how to use a multi-select control with a reactive form.
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* const countryControl = new FormControl();
|
||||
* ```
|
||||
@ -65,9 +65,9 @@ abstract class HTMLCollection {
|
||||
* </option>
|
||||
* </select>
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* ### Customizing option selection
|
||||
*
|
||||
*
|
||||
* To customize the default option comparison algorithm, `<select>` supports `compareWith` input.
|
||||
* See the `SelectControlValueAccessor` for usage.
|
||||
*
|
||||
@ -135,9 +135,13 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
|
||||
if (Array.isArray(value)) {
|
||||
// convert values to ids
|
||||
const ids = value.map((v) => this._getOptionId(v));
|
||||
optionSelectedStateSetter = (opt, o) => { opt._setSelected(ids.indexOf(o.toString()) > -1); };
|
||||
optionSelectedStateSetter = (opt, o) => {
|
||||
opt._setSelected(ids.indexOf(o.toString()) > -1);
|
||||
};
|
||||
} else {
|
||||
optionSelectedStateSetter = (opt, o) => { opt._setSelected(false); };
|
||||
optionSelectedStateSetter = (opt, o) => {
|
||||
opt._setSelected(false);
|
||||
};
|
||||
}
|
||||
this._optionMap.forEach(optionSelectedStateSetter);
|
||||
}
|
||||
@ -182,7 +186,9 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnTouched(fn: () => any): void { this.onTouched = fn; }
|
||||
registerOnTouched(fn: () => any): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "disabled" property on the select input element.
|
||||
@ -203,7 +209,7 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
|
||||
/** @internal */
|
||||
_getOptionId(value: any): string|null {
|
||||
for (const id of Array.from(this._optionMap.keys())) {
|
||||
if (this._compareWith(this._optionMap.get(id) !._value, value)) return id;
|
||||
if (this._compareWith(this._optionMap.get(id)!._value, value)) return id;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -211,7 +217,7 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
|
||||
/** @internal */
|
||||
_getOptionValue(valueString: string): any {
|
||||
const id: string = _extractId(valueString);
|
||||
return this._optionMap.has(id) ? this._optionMap.get(id) !._value : valueString;
|
||||
return this._optionMap.has(id) ? this._optionMap.get(id)!._value : valueString;
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +234,7 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
|
||||
@Directive({selector: 'option'})
|
||||
export class ɵNgSelectMultipleOption implements OnDestroy {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
id !: string;
|
||||
id!: string;
|
||||
/** @internal */
|
||||
_value: any;
|
||||
|
||||
|
@ -28,43 +28,44 @@ import {SelectMultipleControlValueAccessor} from './select_multiple_control_valu
|
||||
import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators';
|
||||
|
||||
|
||||
export function controlPath(name: string | null, parent: ControlContainer): string[] {
|
||||
return [...parent.path !, name !];
|
||||
export function controlPath(name: string|null, parent: ControlContainer): string[] {
|
||||
return [...parent.path!, name!];
|
||||
}
|
||||
|
||||
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');
|
||||
|
||||
control.validator = Validators.compose([control.validator !, dir.validator]);
|
||||
control.asyncValidator = Validators.composeAsync([control.asyncValidator !, dir.asyncValidator]);
|
||||
dir.valueAccessor !.writeValue(control.value);
|
||||
control.validator = Validators.compose([control.validator!, dir.validator]);
|
||||
control.asyncValidator = Validators.composeAsync([control.asyncValidator!, dir.asyncValidator]);
|
||||
dir.valueAccessor!.writeValue(control.value);
|
||||
|
||||
setUpViewChangePipeline(control, dir);
|
||||
setUpModelChangePipeline(control, dir);
|
||||
|
||||
setUpBlurPipeline(control, dir);
|
||||
|
||||
if (dir.valueAccessor !.setDisabledState) {
|
||||
control.registerOnDisabledChange(
|
||||
(isDisabled: boolean) => { dir.valueAccessor !.setDisabledState !(isDisabled); });
|
||||
if (dir.valueAccessor!.setDisabledState) {
|
||||
control.registerOnDisabledChange((isDisabled: boolean) => {
|
||||
dir.valueAccessor!.setDisabledState!(isDisabled);
|
||||
});
|
||||
}
|
||||
|
||||
// re-run validation when validator binding changes, e.g. minlength=3 -> minlength=4
|
||||
dir._rawValidators.forEach((validator: Validator | ValidatorFn) => {
|
||||
dir._rawValidators.forEach((validator: Validator|ValidatorFn) => {
|
||||
if ((<Validator>validator).registerOnValidatorChange)
|
||||
(<Validator>validator).registerOnValidatorChange !(() => control.updateValueAndValidity());
|
||||
(<Validator>validator).registerOnValidatorChange!(() => control.updateValueAndValidity());
|
||||
});
|
||||
|
||||
dir._rawAsyncValidators.forEach((validator: AsyncValidator | AsyncValidatorFn) => {
|
||||
dir._rawAsyncValidators.forEach((validator: AsyncValidator|AsyncValidatorFn) => {
|
||||
if ((<Validator>validator).registerOnValidatorChange)
|
||||
(<Validator>validator).registerOnValidatorChange !(() => control.updateValueAndValidity());
|
||||
(<Validator>validator).registerOnValidatorChange!(() => control.updateValueAndValidity());
|
||||
});
|
||||
}
|
||||
|
||||
export function cleanUpControl(control: FormControl, dir: NgControl) {
|
||||
dir.valueAccessor !.registerOnChange(() => _noControlError(dir));
|
||||
dir.valueAccessor !.registerOnTouched(() => _noControlError(dir));
|
||||
dir.valueAccessor!.registerOnChange(() => _noControlError(dir));
|
||||
dir.valueAccessor!.registerOnTouched(() => _noControlError(dir));
|
||||
|
||||
dir._rawValidators.forEach((validator: any) => {
|
||||
if (validator.registerOnValidatorChange) {
|
||||
@ -82,7 +83,7 @@ export function cleanUpControl(control: FormControl, dir: NgControl) {
|
||||
}
|
||||
|
||||
function setUpViewChangePipeline(control: FormControl, dir: NgControl): void {
|
||||
dir.valueAccessor !.registerOnChange((newValue: any) => {
|
||||
dir.valueAccessor!.registerOnChange((newValue: any) => {
|
||||
control._pendingValue = newValue;
|
||||
control._pendingChange = true;
|
||||
control._pendingDirty = true;
|
||||
@ -92,7 +93,7 @@ function setUpViewChangePipeline(control: FormControl, dir: NgControl): void {
|
||||
}
|
||||
|
||||
function setUpBlurPipeline(control: FormControl, dir: NgControl): void {
|
||||
dir.valueAccessor !.registerOnTouched(() => {
|
||||
dir.valueAccessor!.registerOnTouched(() => {
|
||||
control._pendingTouched = true;
|
||||
|
||||
if (control.updateOn === 'blur' && control._pendingChange) updateControl(control, dir);
|
||||
@ -110,7 +111,7 @@ function updateControl(control: FormControl, dir: NgControl): void {
|
||||
function setUpModelChangePipeline(control: FormControl, dir: NgControl): void {
|
||||
control.registerOnChange((newValue: any, emitModelEvent: boolean) => {
|
||||
// control -> view
|
||||
dir.valueAccessor !.writeValue(newValue);
|
||||
dir.valueAccessor!.writeValue(newValue);
|
||||
|
||||
// control -> ngModel
|
||||
if (emitModelEvent) dir.viewToModelUpdate(newValue);
|
||||
@ -118,7 +119,7 @@ function setUpModelChangePipeline(control: FormControl, dir: NgControl): void {
|
||||
}
|
||||
|
||||
export function setUpFormContainer(
|
||||
control: FormGroup | FormArray, dir: AbstractFormGroupDirective | FormArrayName) {
|
||||
control: FormGroup|FormArray, dir: AbstractFormGroupDirective|FormArrayName) {
|
||||
if (control == null) _throwError(dir, 'Cannot find control with');
|
||||
control.validator = Validators.compose([control.validator, dir.validator]);
|
||||
control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
|
||||
@ -130,9 +131,9 @@ function _noControlError(dir: NgControl) {
|
||||
|
||||
function _throwError(dir: AbstractControlDirective, message: string): void {
|
||||
let messageEnd: string;
|
||||
if (dir.path !.length > 1) {
|
||||
if (dir.path!.length > 1) {
|
||||
messageEnd = `path: '${dir.path!.join(' -> ')}'`;
|
||||
} else if (dir.path ![0]) {
|
||||
} else if (dir.path![0]) {
|
||||
messageEnd = `name: '${dir.path}'`;
|
||||
} else {
|
||||
messageEnd = 'unspecified name attribute';
|
||||
@ -226,7 +227,7 @@ export function removeDir<T>(list: T[], el: T): void {
|
||||
// TODO(kara): remove after deprecation period
|
||||
export function _ngModelWarning(
|
||||
name: string, type: {_ngModelWarningSentOnce: boolean},
|
||||
instance: {_ngModelWarningSent: boolean}, warningConfig: string | null) {
|
||||
instance: {_ngModelWarningSent: boolean}, warningConfig: string|null) {
|
||||
if (!isDevMode() || warningConfig === 'never') return;
|
||||
|
||||
if (((warningConfig === null || warningConfig === 'once') && !type._ngModelWarningSentOnce) ||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, Input, OnChanges, SimpleChanges, StaticProvider, forwardRef} from '@angular/core';
|
||||
import {Directive, forwardRef, Input, OnChanges, SimpleChanges, StaticProvider} from '@angular/core';
|
||||
import {Observable} from 'rxjs';
|
||||
|
||||
import {AbstractControl} from '../model';
|
||||
@ -136,11 +136,11 @@ export const CHECKBOX_REQUIRED_VALIDATOR: StaticProvider = {
|
||||
* @description
|
||||
* A directive that adds the `required` validator to any controls marked with the
|
||||
* `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
||||
*
|
||||
*
|
||||
* @see [Form Validation](guide/form-validation)
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
*
|
||||
* ### Adding a required validator using template-driven forms
|
||||
*
|
||||
* ```
|
||||
@ -159,16 +159,18 @@ export const CHECKBOX_REQUIRED_VALIDATOR: StaticProvider = {
|
||||
})
|
||||
export class RequiredValidator implements Validator {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _required !: boolean;
|
||||
private _required!: boolean;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _onChange !: () => void;
|
||||
private _onChange!: () => void;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Tracks changes to the required attribute bound to this directive.
|
||||
*/
|
||||
@Input()
|
||||
get required(): boolean|string { return this._required; }
|
||||
get required(): boolean|string {
|
||||
return this._required;
|
||||
}
|
||||
|
||||
set required(value: boolean|string) {
|
||||
this._required = value != null && value !== false && `${value}` !== 'false';
|
||||
@ -190,22 +192,25 @@ export class RequiredValidator implements Validator {
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnValidatorChange(fn: () => void): void { this._onChange = fn; }
|
||||
registerOnValidatorChange(fn: () => void): void {
|
||||
this._onChange = fn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A Directive that adds the `required` validator to checkbox controls marked with the
|
||||
* `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
||||
*
|
||||
*
|
||||
* @see [Form Validation](guide/form-validation)
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
*
|
||||
* ### Adding a required checkbox validator using template-driven forms
|
||||
*
|
||||
* The following example shows how to add a checkbox required validator to an input attached to an ngModel binding.
|
||||
*
|
||||
* The following example shows how to add a checkbox required validator to an input attached to an
|
||||
* ngModel binding.
|
||||
*
|
||||
* ```
|
||||
* <input type="checkbox" name="active" ngModel required>
|
||||
* ```
|
||||
@ -248,11 +253,12 @@ export const EMAIL_VALIDATOR: any = {
|
||||
* @see [Form Validation](guide/form-validation)
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
*
|
||||
* ### Adding an email validator
|
||||
*
|
||||
* The following example shows how to add an email validator to an input attached to an ngModel binding.
|
||||
*
|
||||
* The following example shows how to add an email validator to an input attached to an ngModel
|
||||
* binding.
|
||||
*
|
||||
* ```
|
||||
* <input type="email" name="email" ngModel email>
|
||||
* <input type="email" name="email" ngModel email="true">
|
||||
@ -269,9 +275,9 @@ export const EMAIL_VALIDATOR: any = {
|
||||
})
|
||||
export class EmailValidator implements Validator {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _enabled !: boolean;
|
||||
private _enabled!: boolean;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _onChange !: () => void;
|
||||
private _onChange!: () => void;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -298,7 +304,9 @@ export class EmailValidator implements Validator {
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnValidatorChange(fn: () => void): void { this._onChange = fn; }
|
||||
registerOnValidatorChange(fn: () => void): void {
|
||||
this._onChange = fn;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -308,7 +316,9 @@ export class EmailValidator implements Validator {
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export interface ValidatorFn { (control: AbstractControl): ValidationErrors|null; }
|
||||
export interface ValidatorFn {
|
||||
(control: AbstractControl): ValidationErrors|null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -334,7 +344,7 @@ export const MIN_LENGTH_VALIDATOR: any = {
|
||||
/**
|
||||
* A directive that adds minimum length validation to controls marked with the
|
||||
* `minlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
||||
*
|
||||
*
|
||||
* @see [Form Validation](guide/form-validation)
|
||||
*
|
||||
* @usageNotes
|
||||
@ -357,19 +367,18 @@ export const MIN_LENGTH_VALIDATOR: any = {
|
||||
providers: [MIN_LENGTH_VALIDATOR],
|
||||
host: {'[attr.minlength]': 'minlength ? minlength : null'}
|
||||
})
|
||||
export class MinLengthValidator implements Validator,
|
||||
OnChanges {
|
||||
export class MinLengthValidator implements Validator, OnChanges {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _validator !: ValidatorFn;
|
||||
private _validator!: ValidatorFn;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _onChange !: () => void;
|
||||
private _onChange!: () => void;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Tracks changes to the the minimum length bound to this directive.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() minlength !: string | number;
|
||||
@Input() minlength!: string|number;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -400,7 +409,9 @@ export class MinLengthValidator implements Validator,
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnValidatorChange(fn: () => void): void { this._onChange = fn; }
|
||||
registerOnValidatorChange(fn: () => void): void {
|
||||
this._onChange = fn;
|
||||
}
|
||||
|
||||
private _createValidator(): void {
|
||||
this._validator = Validators.minLength(
|
||||
@ -421,7 +432,7 @@ export const MAX_LENGTH_VALIDATOR: any = {
|
||||
/**
|
||||
* A directive that adds max length validation to controls marked with the
|
||||
* `maxlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
||||
*
|
||||
*
|
||||
* @see [Form Validation](guide/form-validation)
|
||||
*
|
||||
* @usageNotes
|
||||
@ -444,19 +455,18 @@ export const MAX_LENGTH_VALIDATOR: any = {
|
||||
providers: [MAX_LENGTH_VALIDATOR],
|
||||
host: {'[attr.maxlength]': 'maxlength ? maxlength : null'}
|
||||
})
|
||||
export class MaxLengthValidator implements Validator,
|
||||
OnChanges {
|
||||
export class MaxLengthValidator implements Validator, OnChanges {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _validator !: ValidatorFn;
|
||||
private _validator!: ValidatorFn;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _onChange !: () => void;
|
||||
private _onChange!: () => void;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Tracks changes to the the maximum length bound to this directive.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() maxlength !: string | number;
|
||||
@Input() maxlength!: string|number;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -487,7 +497,9 @@ export class MaxLengthValidator implements Validator,
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnValidatorChange(fn: () => void): void { this._onChange = fn; }
|
||||
registerOnValidatorChange(fn: () => void): void {
|
||||
this._onChange = fn;
|
||||
}
|
||||
|
||||
private _createValidator(): void {
|
||||
this._validator = Validators.maxLength(
|
||||
@ -511,7 +523,7 @@ export const PATTERN_VALIDATOR: any = {
|
||||
* A directive that adds regex pattern validation to controls marked with the
|
||||
* `pattern` attribute. The regex must match the entire control value.
|
||||
* The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
||||
*
|
||||
*
|
||||
* @see [Form Validation](guide/form-validation)
|
||||
*
|
||||
* @usageNotes
|
||||
@ -524,7 +536,7 @@ export const PATTERN_VALIDATOR: any = {
|
||||
* ```html
|
||||
* <input name="firstName" ngModel pattern="[a-zA-Z ]*">
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @ngModule ReactiveFormsModule
|
||||
* @ngModule FormsModule
|
||||
* @publicApi
|
||||
@ -534,19 +546,18 @@ export const PATTERN_VALIDATOR: any = {
|
||||
providers: [PATTERN_VALIDATOR],
|
||||
host: {'[attr.pattern]': 'pattern ? pattern : null'}
|
||||
})
|
||||
export class PatternValidator implements Validator,
|
||||
OnChanges {
|
||||
export class PatternValidator implements Validator, OnChanges {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _validator !: ValidatorFn;
|
||||
private _validator!: ValidatorFn;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _onChange !: () => void;
|
||||
private _onChange!: () => void;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Tracks changes to the pattern bound to this directive.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() pattern !: string | RegExp;
|
||||
@Input() pattern!: string|RegExp;
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -567,7 +578,9 @@ export class PatternValidator implements Validator,
|
||||
* Method that validates whether the value matches the
|
||||
* the pattern requirement.
|
||||
*/
|
||||
validate(control: AbstractControl): ValidationErrors|null { return this._validator(control); }
|
||||
validate(control: AbstractControl): ValidationErrors|null {
|
||||
return this._validator(control);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -575,7 +588,11 @@ export class PatternValidator implements Validator,
|
||||
*
|
||||
* @param fn The callback function
|
||||
*/
|
||||
registerOnValidatorChange(fn: () => void): void { this._onChange = fn; }
|
||||
registerOnValidatorChange(fn: () => void): void {
|
||||
this._onChange = fn;
|
||||
}
|
||||
|
||||
private _createValidator(): void { this._validator = Validators.pattern(this.pattern); }
|
||||
private _createValidator(): void {
|
||||
this._validator = Validators.pattern(this.pattern);
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import {Injectable} from '@angular/core';
|
||||
import {AsyncValidatorFn, ValidatorFn} from './directives/validators';
|
||||
import {AbstractControl, AbstractControlOptions, FormArray, FormControl, FormGroup, FormHooks} from './model';
|
||||
|
||||
function isAbstractControlOptions(options: AbstractControlOptions | {[key: string]: any}):
|
||||
options is AbstractControlOptions {
|
||||
function isAbstractControlOptions(options: AbstractControlOptions|
|
||||
{[key: string]: any}): options is AbstractControlOptions {
|
||||
return (<AbstractControlOptions>options).asyncValidators !== undefined ||
|
||||
(<AbstractControlOptions>options).validators !== undefined ||
|
||||
(<AbstractControlOptions>options).updateOn !== undefined;
|
||||
|
@ -52,14 +52,13 @@ export class ReactiveFormsModule {
|
||||
* binding is used with reactive form directives.
|
||||
*/
|
||||
static withConfig(opts: {
|
||||
/** @deprecated as of v6 */ warnOnNgModelWithFormControl: 'never' | 'once' | 'always'
|
||||
/** @deprecated as of v6 */ warnOnNgModelWithFormControl: 'never'|'once'|'always'
|
||||
}): ModuleWithProviders<ReactiveFormsModule> {
|
||||
return {
|
||||
ngModule: ReactiveFormsModule,
|
||||
providers: [{
|
||||
provide: NG_MODEL_WITH_FORM_CONTROL_WARNING,
|
||||
useValue: opts.warnOnNgModelWithFormControl
|
||||
}]
|
||||
providers: [
|
||||
{provide: NG_MODEL_WITH_FORM_CONTROL_WARNING, useValue: opts.warnOnNgModelWithFormControl}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ export const PENDING = 'PENDING';
|
||||
*/
|
||||
export const DISABLED = 'DISABLED';
|
||||
|
||||
function _find(control: AbstractControl, path: Array<string|number>| string, delimiter: string) {
|
||||
function _find(control: AbstractControl, path: Array<string|number>|string, delimiter: string) {
|
||||
if (path == null) return null;
|
||||
|
||||
if (!Array.isArray(path)) {
|
||||
@ -55,7 +55,7 @@ function _find(control: AbstractControl, path: Array<string|number>| string, del
|
||||
// Not using Array.reduce here due to a Chrome 80 bug
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
|
||||
let controlToFind: AbstractControl|null = control;
|
||||
path.forEach((name: string | number) => {
|
||||
path.forEach((name: string|number) => {
|
||||
if (controlToFind instanceof FormGroup) {
|
||||
controlToFind = controlToFind.controls.hasOwnProperty(name as string) ?
|
||||
controlToFind.controls[name] :
|
||||
@ -69,9 +69,8 @@ function _find(control: AbstractControl, path: Array<string|number>| string, del
|
||||
return controlToFind;
|
||||
}
|
||||
|
||||
function coerceToValidator(
|
||||
validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null): ValidatorFn|
|
||||
null {
|
||||
function coerceToValidator(validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|
|
||||
null): ValidatorFn|null {
|
||||
const validator =
|
||||
(isOptionsObj(validatorOrOpts) ? (validatorOrOpts as AbstractControlOptions).validators :
|
||||
validatorOrOpts) as ValidatorFn |
|
||||
@ -81,8 +80,9 @@ function coerceToValidator(
|
||||
}
|
||||
|
||||
function coerceToAsyncValidator(
|
||||
asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null, validatorOrOpts?: ValidatorFn |
|
||||
ValidatorFn[] | AbstractControlOptions | null): AsyncValidatorFn|null {
|
||||
asyncValidator?: AsyncValidatorFn|AsyncValidatorFn[]|null,
|
||||
validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null): AsyncValidatorFn|
|
||||
null {
|
||||
const origAsyncValidator =
|
||||
(isOptionsObj(validatorOrOpts) ? (validatorOrOpts as AbstractControlOptions).asyncValidators :
|
||||
asyncValidator) as AsyncValidatorFn |
|
||||
@ -92,7 +92,7 @@ function coerceToAsyncValidator(
|
||||
origAsyncValidator || null;
|
||||
}
|
||||
|
||||
export type FormHooks = 'change' | 'blur' | 'submit';
|
||||
export type FormHooks = 'change'|'blur'|'submit';
|
||||
|
||||
/**
|
||||
* Interface for options provided to an `AbstractControl`.
|
||||
@ -118,8 +118,8 @@ export interface AbstractControlOptions {
|
||||
}
|
||||
|
||||
|
||||
function isOptionsObj(
|
||||
validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null): boolean {
|
||||
function isOptionsObj(validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|
|
||||
null): boolean {
|
||||
return validatorOrOpts != null && !Array.isArray(validatorOrOpts) &&
|
||||
typeof validatorOrOpts === 'object';
|
||||
}
|
||||
@ -142,21 +142,21 @@ function isOptionsObj(
|
||||
export abstract class AbstractControl {
|
||||
/** @internal */
|
||||
// TODO(issue/24571): remove '!'.
|
||||
_pendingDirty !: boolean;
|
||||
_pendingDirty!: boolean;
|
||||
|
||||
/** @internal */
|
||||
// TODO(issue/24571): remove '!'.
|
||||
_pendingTouched !: boolean;
|
||||
_pendingTouched!: boolean;
|
||||
|
||||
/** @internal */
|
||||
_onCollectionChange = () => {};
|
||||
|
||||
/** @internal */
|
||||
// TODO(issue/24571): remove '!'.
|
||||
_updateOn !: FormHooks;
|
||||
_updateOn!: FormHooks;
|
||||
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _parent !: FormGroup | FormArray;
|
||||
private _parent!: FormGroup|FormArray;
|
||||
private _asyncValidationSubscription: any;
|
||||
|
||||
/**
|
||||
@ -184,7 +184,9 @@ export abstract class AbstractControl {
|
||||
/**
|
||||
* The parent control.
|
||||
*/
|
||||
get parent(): FormGroup|FormArray { return this._parent; }
|
||||
get parent(): FormGroup|FormArray {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* The validation status of the control. There are four possible
|
||||
@ -199,7 +201,7 @@ export abstract class AbstractControl {
|
||||
* both valid AND invalid or invalid AND disabled.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
public readonly status !: string;
|
||||
public readonly status!: string;
|
||||
|
||||
/**
|
||||
* A control is `valid` when its `status` is `VALID`.
|
||||
@ -209,7 +211,9 @@ export abstract class AbstractControl {
|
||||
* @returns True if the control has passed all of its validation tests,
|
||||
* false otherwise.
|
||||
*/
|
||||
get valid(): boolean { return this.status === VALID; }
|
||||
get valid(): boolean {
|
||||
return this.status === VALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* A control is `invalid` when its `status` is `INVALID`.
|
||||
@ -219,7 +223,9 @@ export abstract class AbstractControl {
|
||||
* @returns True if this control has failed one or more of its validation checks,
|
||||
* false otherwise.
|
||||
*/
|
||||
get invalid(): boolean { return this.status === INVALID; }
|
||||
get invalid(): boolean {
|
||||
return this.status === INVALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* A control is `pending` when its `status` is `PENDING`.
|
||||
@ -229,7 +235,9 @@ export abstract class AbstractControl {
|
||||
* @returns True if this control is in the process of conducting a validation check,
|
||||
* false otherwise.
|
||||
*/
|
||||
get pending(): boolean { return this.status == PENDING; }
|
||||
get pending(): boolean {
|
||||
return this.status == PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* A control is `disabled` when its `status` is `DISABLED`.
|
||||
@ -242,7 +250,9 @@ export abstract class AbstractControl {
|
||||
*
|
||||
* @returns True if the control is disabled, false otherwise.
|
||||
*/
|
||||
get disabled(): boolean { return this.status === DISABLED; }
|
||||
get disabled(): boolean {
|
||||
return this.status === DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* A control is `enabled` as long as its `status` is not `DISABLED`.
|
||||
@ -253,14 +263,16 @@ export abstract class AbstractControl {
|
||||
* @see {@link AbstractControl.status}
|
||||
*
|
||||
*/
|
||||
get enabled(): boolean { return this.status !== DISABLED; }
|
||||
get enabled(): boolean {
|
||||
return this.status !== DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object containing any errors generated by failing validation,
|
||||
* or null if there are no errors.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
public readonly errors !: ValidationErrors | null;
|
||||
public readonly errors!: ValidationErrors|null;
|
||||
|
||||
/**
|
||||
* A control is `pristine` if the user has not yet changed
|
||||
@ -278,7 +290,9 @@ export abstract class AbstractControl {
|
||||
* @returns True if the user has changed the value of this control in the UI; compare `pristine`.
|
||||
* Programmatic changes to a control's value do not mark it dirty.
|
||||
*/
|
||||
get dirty(): boolean { return !this.pristine; }
|
||||
get dirty(): boolean {
|
||||
return !this.pristine;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the control is marked as `touched`.
|
||||
@ -294,7 +308,9 @@ export abstract class AbstractControl {
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* A multicasting observable that emits an event every time the value of the control changes, in
|
||||
@ -302,7 +318,7 @@ export abstract class AbstractControl {
|
||||
* without passing along {emitEvent: false} as a function argument.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
public readonly valueChanges !: Observable<any>;
|
||||
public readonly valueChanges!: Observable<any>;
|
||||
|
||||
/**
|
||||
* A multicasting observable that emits an event every time the validation `status` of the control
|
||||
@ -312,7 +328,7 @@ export abstract class AbstractControl {
|
||||
*
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
public readonly statusChanges !: Observable<any>;
|
||||
public readonly statusChanges!: Observable<any>;
|
||||
|
||||
/**
|
||||
* Reports the update strategy of the `AbstractControl` (meaning
|
||||
@ -355,7 +371,9 @@ export abstract class AbstractControl {
|
||||
* `updateValueAndValidity()` for the new validation to take effect.
|
||||
*
|
||||
*/
|
||||
clearValidators(): void { this.validator = null; }
|
||||
clearValidators(): void {
|
||||
this.validator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empties out the async validator list.
|
||||
@ -364,7 +382,9 @@ export abstract class AbstractControl {
|
||||
* `updateValueAndValidity()` for the new validation to take effect.
|
||||
*
|
||||
*/
|
||||
clearAsyncValidators(): void { this.asyncValidator = null; }
|
||||
clearAsyncValidators(): void {
|
||||
this.asyncValidator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the control as `touched`. A control is touched by focus and
|
||||
@ -380,7 +400,7 @@ export abstract class AbstractControl {
|
||||
* marks all direct ancestors. Default is false.
|
||||
*/
|
||||
markAsTouched(opts: {onlySelf?: boolean} = {}): void {
|
||||
(this as{touched: boolean}).touched = true;
|
||||
(this as {touched: boolean}).touched = true;
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent.markAsTouched(opts);
|
||||
@ -413,11 +433,12 @@ export abstract class AbstractControl {
|
||||
* marks all direct ancestors. Default is false.
|
||||
*/
|
||||
markAsUntouched(opts: {onlySelf?: boolean} = {}): void {
|
||||
(this as{touched: boolean}).touched = false;
|
||||
(this as {touched: boolean}).touched = false;
|
||||
this._pendingTouched = false;
|
||||
|
||||
this._forEachChild(
|
||||
(control: AbstractControl) => { control.markAsUntouched({onlySelf: true}); });
|
||||
this._forEachChild((control: AbstractControl) => {
|
||||
control.markAsUntouched({onlySelf: true});
|
||||
});
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent._updateTouched(opts);
|
||||
@ -438,7 +459,7 @@ export abstract class AbstractControl {
|
||||
* marks all direct ancestors. Default is false.
|
||||
*/
|
||||
markAsDirty(opts: {onlySelf?: boolean} = {}): void {
|
||||
(this as{pristine: boolean}).pristine = false;
|
||||
(this as {pristine: boolean}).pristine = false;
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent.markAsDirty(opts);
|
||||
@ -462,10 +483,12 @@ export abstract class AbstractControl {
|
||||
* marks all direct ancestors. Default is false..
|
||||
*/
|
||||
markAsPristine(opts: {onlySelf?: boolean} = {}): void {
|
||||
(this as{pristine: boolean}).pristine = true;
|
||||
(this as {pristine: boolean}).pristine = true;
|
||||
this._pendingDirty = false;
|
||||
|
||||
this._forEachChild((control: AbstractControl) => { control.markAsPristine({onlySelf: true}); });
|
||||
this._forEachChild((control: AbstractControl) => {
|
||||
control.markAsPristine({onlySelf: true});
|
||||
});
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent._updatePristine(opts);
|
||||
@ -489,7 +512,7 @@ export abstract class AbstractControl {
|
||||
*
|
||||
*/
|
||||
markAsPending(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
|
||||
(this as{status: string}).status = PENDING;
|
||||
(this as {status: string}).status = PENDING;
|
||||
|
||||
if (opts.emitEvent !== false) {
|
||||
(this.statusChanges as EventEmitter<any>).emit(this.status);
|
||||
@ -522,10 +545,11 @@ export abstract class AbstractControl {
|
||||
// parent's dirtiness based on the children.
|
||||
const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf);
|
||||
|
||||
(this as{status: string}).status = DISABLED;
|
||||
(this as{errors: ValidationErrors | null}).errors = null;
|
||||
this._forEachChild(
|
||||
(control: AbstractControl) => { control.disable({...opts, onlySelf: true}); });
|
||||
(this as {status: string}).status = DISABLED;
|
||||
(this as {errors: ValidationErrors | null}).errors = null;
|
||||
this._forEachChild((control: AbstractControl) => {
|
||||
control.disable({...opts, onlySelf: true});
|
||||
});
|
||||
this._updateValue();
|
||||
|
||||
if (opts.emitEvent !== false) {
|
||||
@ -560,9 +584,10 @@ export abstract class AbstractControl {
|
||||
// parent's dirtiness based on the children.
|
||||
const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf);
|
||||
|
||||
(this as{status: string}).status = VALID;
|
||||
this._forEachChild(
|
||||
(control: AbstractControl) => { control.enable({...opts, onlySelf: true}); });
|
||||
(this as {status: string}).status = VALID;
|
||||
this._forEachChild((control: AbstractControl) => {
|
||||
control.enable({...opts, onlySelf: true});
|
||||
});
|
||||
this.updateValueAndValidity({onlySelf: true, emitEvent: opts.emitEvent});
|
||||
|
||||
this._updateAncestors({...opts, skipPristineCheck});
|
||||
@ -583,7 +608,9 @@ export abstract class AbstractControl {
|
||||
/**
|
||||
* @param parent Sets the parent of the control
|
||||
*/
|
||||
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).
|
||||
@ -620,8 +647,8 @@ export abstract class AbstractControl {
|
||||
|
||||
if (this.enabled) {
|
||||
this._cancelExistingSubscription();
|
||||
(this as{errors: ValidationErrors | null}).errors = this._runValidator();
|
||||
(this as{status: string}).status = this._calculateStatus();
|
||||
(this as {errors: ValidationErrors | null}).errors = this._runValidator();
|
||||
(this as {status: string}).status = this._calculateStatus();
|
||||
|
||||
if (this.status === VALID || this.status === PENDING) {
|
||||
this._runAsyncValidator(opts.emitEvent);
|
||||
@ -645,7 +672,7 @@ export abstract class AbstractControl {
|
||||
}
|
||||
|
||||
private _setInitialStatus() {
|
||||
(this as{status: string}).status = this._allControlsDisabled() ? DISABLED : VALID;
|
||||
(this as {status: string}).status = this._allControlsDisabled() ? DISABLED : VALID;
|
||||
}
|
||||
|
||||
private _runValidator(): ValidationErrors|null {
|
||||
@ -654,10 +681,10 @@ export abstract class AbstractControl {
|
||||
|
||||
private _runAsyncValidator(emitEvent?: boolean): void {
|
||||
if (this.asyncValidator) {
|
||||
(this as{status: string}).status = PENDING;
|
||||
(this as {status: string}).status = PENDING;
|
||||
const obs = toObservable(this.asyncValidator(this));
|
||||
this._asyncValidationSubscription =
|
||||
obs.subscribe((errors: ValidationErrors | null) => this.setErrors(errors, {emitEvent}));
|
||||
obs.subscribe((errors: ValidationErrors|null) => this.setErrors(errors, {emitEvent}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,7 +717,7 @@ export abstract class AbstractControl {
|
||||
* ```
|
||||
*/
|
||||
setErrors(errors: ValidationErrors|null, opts: {emitEvent?: boolean} = {}): void {
|
||||
(this as{errors: ValidationErrors | null}).errors = errors;
|
||||
(this as {errors: ValidationErrors | null}).errors = errors;
|
||||
this._updateControlsErrors(opts.emitEvent !== false);
|
||||
}
|
||||
|
||||
@ -711,7 +738,9 @@ export abstract class AbstractControl {
|
||||
*
|
||||
* * `this.form.get(['person', 'name']);`
|
||||
*/
|
||||
get(path: Array<string|number>|string): AbstractControl|null { return _find(this, path, '.'); }
|
||||
get(path: Array<string|number>|string): AbstractControl|null {
|
||||
return _find(this, path, '.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -794,7 +823,7 @@ export abstract class AbstractControl {
|
||||
|
||||
/** @internal */
|
||||
_updateControlsErrors(emitEvent: boolean): void {
|
||||
(this as{status: string}).status = this._calculateStatus();
|
||||
(this as {status: string}).status = this._calculateStatus();
|
||||
|
||||
if (emitEvent) {
|
||||
(this.statusChanges as EventEmitter<string>).emit(this.status);
|
||||
@ -807,8 +836,8 @@ export abstract class AbstractControl {
|
||||
|
||||
/** @internal */
|
||||
_initObservables() {
|
||||
(this as{valueChanges: Observable<any>}).valueChanges = new EventEmitter();
|
||||
(this as{statusChanges: Observable<any>}).statusChanges = new EventEmitter();
|
||||
(this as {valueChanges: Observable<any>}).valueChanges = new EventEmitter();
|
||||
(this as {statusChanges: Observable<any>}).statusChanges = new EventEmitter();
|
||||
}
|
||||
|
||||
|
||||
@ -852,7 +881,7 @@ export abstract class AbstractControl {
|
||||
|
||||
/** @internal */
|
||||
_updatePristine(opts: {onlySelf?: boolean} = {}): void {
|
||||
(this as{pristine: boolean}).pristine = !this._anyControlsDirty();
|
||||
(this as {pristine: boolean}).pristine = !this._anyControlsDirty();
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent._updatePristine(opts);
|
||||
@ -861,7 +890,7 @@ export abstract class AbstractControl {
|
||||
|
||||
/** @internal */
|
||||
_updateTouched(opts: {onlySelf?: boolean} = {}): void {
|
||||
(this as{touched: boolean}).touched = this._anyControlsTouched();
|
||||
(this as {touched: boolean}).touched = this._anyControlsTouched();
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent._updateTouched(opts);
|
||||
@ -878,12 +907,14 @@ export abstract class AbstractControl {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_registerOnCollectionChange(fn: () => void): void { this._onCollectionChange = fn; }
|
||||
_registerOnCollectionChange(fn: () => void): void {
|
||||
this._onCollectionChange = fn;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_setUpdateStrategy(opts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null): void {
|
||||
if (isOptionsObj(opts) && (opts as AbstractControlOptions).updateOn != null) {
|
||||
this._updateOn = (opts as AbstractControlOptions).updateOn !;
|
||||
this._updateOn = (opts as AbstractControlOptions).updateOn!;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1006,18 +1037,18 @@ export class FormControl extends AbstractControl {
|
||||
_pendingChange: any;
|
||||
|
||||
/**
|
||||
* Creates a new `FormControl` instance.
|
||||
*
|
||||
* @param formState Initializes the control with an initial value,
|
||||
* or an object that defines the initial value and disabled state.
|
||||
*
|
||||
* @param validatorOrOpts A synchronous validator function, or an array of
|
||||
* such functions, or an `AbstractControlOptions` object that contains validation functions
|
||||
* and a validation trigger.
|
||||
*
|
||||
* @param asyncValidator A single async validator or array of async validator functions
|
||||
*
|
||||
*/
|
||||
* Creates a new `FormControl` instance.
|
||||
*
|
||||
* @param formState Initializes the control with an initial value,
|
||||
* or an object that defines the initial value and disabled state.
|
||||
*
|
||||
* @param validatorOrOpts A synchronous validator function, or an array of
|
||||
* such functions, or an `AbstractControlOptions` object that contains validation functions
|
||||
* and a validation trigger.
|
||||
*
|
||||
* @param asyncValidator A single async validator or array of async validator functions
|
||||
*
|
||||
*/
|
||||
constructor(
|
||||
formState: any = null,
|
||||
validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null,
|
||||
@ -1060,7 +1091,7 @@ export class FormControl extends AbstractControl {
|
||||
emitModelToViewChange?: boolean,
|
||||
emitViewToModelChange?: boolean
|
||||
} = {}): void {
|
||||
(this as{value: any}).value = this._pendingValue = value;
|
||||
(this as {value: any}).value = this._pendingValue = value;
|
||||
if (this._onChange.length && options.emitModelToViewChange !== false) {
|
||||
this._onChange.forEach(
|
||||
(changeFn) => changeFn(this.value, options.emitViewToModelChange !== false));
|
||||
@ -1120,19 +1151,25 @@ export class FormControl extends AbstractControl {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_anyControls(condition: Function): boolean { return false; }
|
||||
_anyControls(condition: Function): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_allControlsDisabled(): boolean { return this.disabled; }
|
||||
_allControlsDisabled(): boolean {
|
||||
return this.disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a listener for change events.
|
||||
*
|
||||
* @param fn The method that is called when the value changes
|
||||
*/
|
||||
registerOnChange(fn: Function): void { this._onChange.push(fn); }
|
||||
registerOnChange(fn: Function): void {
|
||||
this._onChange.push(fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -1172,11 +1209,11 @@ export class FormControl extends AbstractControl {
|
||||
|
||||
private _applyFormState(formState: any) {
|
||||
if (this._isBoxedValue(formState)) {
|
||||
(this as{value: any}).value = this._pendingValue = formState.value;
|
||||
(this as {value: any}).value = this._pendingValue = formState.value;
|
||||
formState.disabled ? this.disable({onlySelf: true, emitEvent: false}) :
|
||||
this.enable({onlySelf: true, emitEvent: false});
|
||||
} else {
|
||||
(this as{value: any}).value = this._pendingValue = formState;
|
||||
(this as {value: any}).value = this._pendingValue = formState;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1255,18 +1292,18 @@ export class FormControl extends AbstractControl {
|
||||
*/
|
||||
export class FormGroup extends AbstractControl {
|
||||
/**
|
||||
* Creates a new `FormGroup` instance.
|
||||
*
|
||||
* @param controls A collection of child controls. The key for each child is the name
|
||||
* under which it is registered.
|
||||
*
|
||||
* @param validatorOrOpts A synchronous validator function, or an array of
|
||||
* such functions, or an `AbstractControlOptions` object that contains validation functions
|
||||
* and a validation trigger.
|
||||
*
|
||||
* @param asyncValidator A single async validator or array of async validator functions
|
||||
*
|
||||
*/
|
||||
* Creates a new `FormGroup` instance.
|
||||
*
|
||||
* @param controls A collection of child controls. The key for each child is the name
|
||||
* under which it is registered.
|
||||
*
|
||||
* @param validatorOrOpts A synchronous validator function, or an array of
|
||||
* such functions, or an `AbstractControlOptions` object that contains validation functions
|
||||
* and a validation trigger.
|
||||
*
|
||||
* @param asyncValidator A single async validator or array of async validator functions
|
||||
*
|
||||
*/
|
||||
constructor(
|
||||
public controls: {[key: string]: AbstractControl},
|
||||
validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null,
|
||||
@ -1556,7 +1593,9 @@ export class FormGroup extends AbstractControl {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_updateValue(): void { (this as{value: any}).value = this._reduceValue(); }
|
||||
_updateValue(): void {
|
||||
(this as {value: any}).value = this._reduceValue();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_anyControls(condition: Function): boolean {
|
||||
@ -1581,8 +1620,9 @@ export class FormGroup extends AbstractControl {
|
||||
/** @internal */
|
||||
_reduceChildren(initValue: any, fn: Function) {
|
||||
let res = initValue;
|
||||
this._forEachChild(
|
||||
(control: AbstractControl, name: string) => { res = fn(res, control, name); });
|
||||
this._forEachChild((control: AbstractControl, name: string) => {
|
||||
res = fn(res, control, name);
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1647,7 +1687,7 @@ export class FormGroup extends AbstractControl {
|
||||
* ], {validators: myValidator, asyncValidators: myAsyncValidator});
|
||||
* ```
|
||||
*
|
||||
* ### Set the updateOn property for all controls in a form array
|
||||
* ### Set the updateOn property for all controls in a form array
|
||||
*
|
||||
* The options object is used to set a default value for each child
|
||||
* control's `updateOn` property. If you set `updateOn` to `'blur'` at the
|
||||
@ -1672,18 +1712,18 @@ export class FormGroup extends AbstractControl {
|
||||
*/
|
||||
export class FormArray extends AbstractControl {
|
||||
/**
|
||||
* Creates a new `FormArray` instance.
|
||||
*
|
||||
* @param controls An array of child controls. Each child control is given an index
|
||||
* where it is registered.
|
||||
*
|
||||
* @param validatorOrOpts A synchronous validator function, or an array of
|
||||
* such functions, or an `AbstractControlOptions` object that contains validation functions
|
||||
* and a validation trigger.
|
||||
*
|
||||
* @param asyncValidator A single async validator or array of async validator functions
|
||||
*
|
||||
*/
|
||||
* Creates a new `FormArray` instance.
|
||||
*
|
||||
* @param controls An array of child controls. Each child control is given an index
|
||||
* where it is registered.
|
||||
*
|
||||
* @param validatorOrOpts A synchronous validator function, or an array of
|
||||
* such functions, or an `AbstractControlOptions` object that contains validation functions
|
||||
* and a validation trigger.
|
||||
*
|
||||
* @param asyncValidator A single async validator or array of async validator functions
|
||||
*
|
||||
*/
|
||||
constructor(
|
||||
public controls: AbstractControl[],
|
||||
validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null,
|
||||
@ -1702,7 +1742,9 @@ export class FormArray extends AbstractControl {
|
||||
*
|
||||
* @param index Index in the array to retrieve the control
|
||||
*/
|
||||
at(index: number): AbstractControl { return this.controls[index]; }
|
||||
at(index: number): AbstractControl {
|
||||
return this.controls[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new `AbstractControl` at the end of the array.
|
||||
@ -1762,7 +1804,9 @@ export class FormArray extends AbstractControl {
|
||||
/**
|
||||
* Length of the control array.
|
||||
*/
|
||||
get length(): number { return this.controls.length; }
|
||||
get length(): number {
|
||||
return this.controls.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the `FormArray`. It accepts an array that matches
|
||||
@ -1979,12 +2023,14 @@ export class FormArray extends AbstractControl {
|
||||
|
||||
/** @internal */
|
||||
_forEachChild(cb: Function): void {
|
||||
this.controls.forEach((control: AbstractControl, index: number) => { cb(control, index); });
|
||||
this.controls.forEach((control: AbstractControl, index: number) => {
|
||||
cb(control, index);
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_updateValue(): void {
|
||||
(this as{value: any}).value =
|
||||
(this as {value: any}).value =
|
||||
this.controls.filter((control) => control.enabled || this.disabled)
|
||||
.map((control) => control.value);
|
||||
}
|
||||
|
@ -7,8 +7,9 @@
|
||||
*/
|
||||
|
||||
import {InjectionToken, ɵisObservable as isObservable, ɵisPromise as isPromise} from '@angular/core';
|
||||
import {Observable, forkJoin, from} from 'rxjs';
|
||||
import {forkJoin, from, Observable} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
|
||||
import {AsyncValidatorFn, ValidationErrors, Validator, ValidatorFn} from './directives/validators';
|
||||
import {AbstractControl, FormControl} from './model';
|
||||
|
||||
@ -19,7 +20,8 @@ function isEmptyInputValue(value: any): boolean {
|
||||
|
||||
/**
|
||||
* @description
|
||||
* An `InjectionToken` for registering additional synchronous validators used with `AbstractControl`s.
|
||||
* An `InjectionToken` for registering additional synchronous validators used with
|
||||
* `AbstractControl`s.
|
||||
*
|
||||
* @see `NG_ASYNC_VALIDATORS`
|
||||
*
|
||||
@ -48,7 +50,8 @@ export const NG_VALIDATORS = new InjectionToken<Array<Validator|Function>>('NgVa
|
||||
|
||||
/**
|
||||
* @description
|
||||
* An `InjectionToken` for registering additional asynchronous validators used with `AbstractControl`s.
|
||||
* An `InjectionToken` for registering additional asynchronous validators used with
|
||||
* `AbstractControl`s.
|
||||
*
|
||||
* @see `NG_VALIDATORS`
|
||||
*
|
||||
@ -124,7 +127,7 @@ export class Validators {
|
||||
*
|
||||
*/
|
||||
static min(min: number): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return (control: AbstractControl): ValidationErrors|null => {
|
||||
if (isEmptyInputValue(control.value) || isEmptyInputValue(min)) {
|
||||
return null; // don't validate empty values to allow optional controls
|
||||
}
|
||||
@ -157,7 +160,7 @@ export class Validators {
|
||||
*
|
||||
*/
|
||||
static max(max: number): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return (control: AbstractControl): ValidationErrors|null => {
|
||||
if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) {
|
||||
return null; // don't validate empty values to allow optional controls
|
||||
}
|
||||
@ -221,11 +224,13 @@ export class Validators {
|
||||
* @description
|
||||
* Validator that requires the control's value pass an email validation test.
|
||||
*
|
||||
* Tests the value using a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
|
||||
* Tests the value using a [regular
|
||||
* expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
|
||||
* pattern suitable for common usecases. The pattern is based on the definition of a valid email
|
||||
* address in the [WHATWG HTML specification](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address)
|
||||
* with some enhancements to incorporate more RFC rules (such as rules related to domain names and
|
||||
* the lengths of different parts of the address).
|
||||
* address in the [WHATWG HTML
|
||||
* specification](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) with
|
||||
* some enhancements to incorporate more RFC rules (such as rules related to domain names and the
|
||||
* lengths of different parts of the address).
|
||||
*
|
||||
* The differences from the WHATWG version include:
|
||||
* - Disallow `local-part` (the part before the `@` symbol) to begin or end with a period (`.`).
|
||||
@ -285,7 +290,7 @@ export class Validators {
|
||||
*
|
||||
*/
|
||||
static minLength(minLength: number): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return (control: AbstractControl): ValidationErrors|null => {
|
||||
if (isEmptyInputValue(control.value)) {
|
||||
return null; // don't validate empty values to allow optional controls
|
||||
}
|
||||
@ -323,7 +328,7 @@ export class Validators {
|
||||
*
|
||||
*/
|
||||
static maxLength(maxLength: number): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return (control: AbstractControl): ValidationErrors|null => {
|
||||
const length: number = control.value ? control.value.length : 0;
|
||||
return length > maxLength ?
|
||||
{'maxlength': {'requiredLength': maxLength, 'actualLength': length}} :
|
||||
@ -379,7 +384,7 @@ export class Validators {
|
||||
regexStr = pattern.toString();
|
||||
regex = pattern;
|
||||
}
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return (control: AbstractControl): ValidationErrors|null => {
|
||||
if (isEmptyInputValue(control.value)) {
|
||||
return null; // don't validate empty values to allow optional controls
|
||||
}
|
||||
@ -396,7 +401,9 @@ export class Validators {
|
||||
* @see `updateValueAndValidity()`
|
||||
*
|
||||
*/
|
||||
static nullValidator(control: AbstractControl): ValidationErrors|null { return null; }
|
||||
static nullValidator(control: AbstractControl): ValidationErrors|null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -469,8 +476,8 @@ function _mergeErrors(arrayOfErrors: ValidationErrors[]): ValidationErrors|null
|
||||
|
||||
// Not using Array.reduce here due to a Chrome 80 bug
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
|
||||
arrayOfErrors.forEach((errors: ValidationErrors | null) => {
|
||||
res = errors != null ? {...res !, ...errors} : res !;
|
||||
arrayOfErrors.forEach((errors: ValidationErrors|null) => {
|
||||
res = errors != null ? {...res!, ...errors} : res!;
|
||||
});
|
||||
|
||||
return Object.keys(res).length === 0 ? null : res;
|
||||
|
Reference in New Issue
Block a user