diff --git a/goldens/public-api/forms/forms.d.ts b/goldens/public-api/forms/forms.d.ts index da3f7bc85d..34271f8e13 100644 --- a/goldens/public-api/forms/forms.d.ts +++ b/goldens/public-api/forms/forms.d.ts @@ -112,13 +112,7 @@ export declare interface AsyncValidatorFn { (control: AbstractControl): Promise | Observable; } -export declare class CheckboxControlValueAccessor extends ɵangular_packages_forms_forms_f implements ControlValueAccessor { - onChange: (_: any) => void; - onTouched: () => void; - constructor(_renderer: Renderer2, _elementRef: ElementRef); - registerOnChange(fn: (_: any) => {}): void; - registerOnTouched(fn: () => {}): void; - setDisabledState(isDisabled: boolean): void; +export declare class CheckboxControlValueAccessor extends ɵangular_packages_forms_forms_g implements ControlValueAccessor { writeValue(value: any): void; } @@ -141,13 +135,8 @@ export declare interface ControlValueAccessor { writeValue(obj: any): void; } -export declare class DefaultValueAccessor implements ControlValueAccessor { - onChange: (_: any) => void; - onTouched: () => void; - constructor(_renderer: Renderer2, _elementRef: ElementRef, _compositionMode: boolean); - registerOnChange(fn: (_: any) => void): void; - registerOnTouched(fn: () => void): void; - setDisabledState(isDisabled: boolean): void; +export declare class DefaultValueAccessor extends ɵangular_packages_forms_forms_f implements ControlValueAccessor { + constructor(renderer: Renderer2, elementRef: ElementRef, _compositionMode: boolean); writeValue(value: any): void; } @@ -382,11 +371,11 @@ export declare abstract class NgControl extends AbstractControlDirective { abstract viewToModelUpdate(newValue: any): void; } -export declare class NgControlStatus extends ɵangular_packages_forms_forms_h { +export declare class NgControlStatus extends ɵangular_packages_forms_forms_i { constructor(cd: NgControl); } -export declare class NgControlStatusGroup extends ɵangular_packages_forms_forms_h { +export declare class NgControlStatusGroup extends ɵangular_packages_forms_forms_i { constructor(cd: ControlContainer); } @@ -454,13 +443,8 @@ export declare class NgSelectOption implements OnDestroy { ngOnDestroy(): void; } -export declare class NumberValueAccessor extends ɵangular_packages_forms_forms_f implements ControlValueAccessor { - onChange: (_: any) => void; - onTouched: () => void; - constructor(_renderer: Renderer2, _elementRef: ElementRef); +export declare class NumberValueAccessor extends ɵangular_packages_forms_forms_g implements ControlValueAccessor { registerOnChange(fn: (_: number | null) => void): void; - registerOnTouched(fn: () => void): void; - setDisabledState(isDisabled: boolean): void; writeValue(value: number): void; } @@ -471,29 +455,21 @@ export declare class PatternValidator implements Validator, OnChanges { validate(control: AbstractControl): ValidationErrors | null; } -export declare class RadioControlValueAccessor extends ɵangular_packages_forms_forms_f implements ControlValueAccessor, OnDestroy, OnInit { +export declare class RadioControlValueAccessor extends ɵangular_packages_forms_forms_g implements ControlValueAccessor, OnDestroy, OnInit { formControlName: string; name: string; onChange: () => void; - onTouched: () => void; value: any; - constructor(_renderer: Renderer2, _elementRef: ElementRef, _registry: ɵangular_packages_forms_forms_p, _injector: Injector); + constructor(renderer: Renderer2, elementRef: ElementRef, _registry: ɵangular_packages_forms_forms_q, _injector: Injector); fireUncheck(value: any): void; ngOnDestroy(): void; ngOnInit(): void; registerOnChange(fn: (_: any) => {}): void; - registerOnTouched(fn: () => {}): void; - setDisabledState(isDisabled: boolean): void; writeValue(value: any): void; } -export declare class RangeValueAccessor extends ɵangular_packages_forms_forms_f implements ControlValueAccessor { - onChange: (_: any) => void; - onTouched: () => void; - constructor(_renderer: Renderer2, _elementRef: ElementRef); +export declare class RangeValueAccessor extends ɵangular_packages_forms_forms_g implements ControlValueAccessor { registerOnChange(fn: (_: number | null) => void): void; - registerOnTouched(fn: () => void): void; - setDisabledState(isDisabled: boolean): void; writeValue(value: any): void; } @@ -509,27 +485,17 @@ export declare class RequiredValidator implements Validator { validate(control: AbstractControl): ValidationErrors | null; } -export declare class SelectControlValueAccessor extends ɵangular_packages_forms_forms_f implements ControlValueAccessor { +export declare class SelectControlValueAccessor extends ɵangular_packages_forms_forms_g implements ControlValueAccessor { set compareWith(fn: (o1: any, o2: any) => boolean); - onChange: (_: any) => void; - onTouched: () => void; value: any; - constructor(_renderer: Renderer2, _elementRef: ElementRef); registerOnChange(fn: (value: any) => any): void; - registerOnTouched(fn: () => any): void; - setDisabledState(isDisabled: boolean): void; writeValue(value: any): void; } -export declare class SelectMultipleControlValueAccessor extends ɵangular_packages_forms_forms_f implements ControlValueAccessor { +export declare class SelectMultipleControlValueAccessor extends ɵangular_packages_forms_forms_g implements ControlValueAccessor { set compareWith(fn: (o1: any, o2: any) => boolean); - onChange: (_: any) => void; - onTouched: () => void; value: any; - constructor(_renderer: Renderer2, _elementRef: ElementRef); registerOnChange(fn: (value: any) => any): void; - registerOnTouched(fn: () => any): void; - setDisabledState(isDisabled: boolean): void; writeValue(value: any): void; } diff --git a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json index 07bd65c2d5..24aa2c30ed 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -44,6 +44,9 @@ { "name": "BROWSER_MODULE_PROVIDERS" }, + { + "name": "BaseControlValueAccessor" + }, { "name": "BrowserDomAdapter" }, @@ -1637,6 +1640,9 @@ { "name": "ɵɵelementStart" }, + { + "name": "ɵɵgetInheritedFactory" + }, { "name": "ɵɵinject" }, diff --git a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json index a5bc8195ca..41dfa4ebe2 100644 --- a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json @@ -44,6 +44,9 @@ { "name": "BROWSER_MODULE_PROVIDERS" }, + { + "name": "BaseControlValueAccessor" + }, { "name": "BrowserDomAdapter" }, @@ -1616,6 +1619,9 @@ { "name": "ɵɵelementStart" }, + { + "name": "ɵɵgetInheritedFactory" + }, { "name": "ɵɵinject" }, diff --git a/packages/forms/src/directives/checkbox_value_accessor.ts b/packages/forms/src/directives/checkbox_value_accessor.ts index c2d97e19c8..ed126c20b7 100644 --- a/packages/forms/src/directives/checkbox_value_accessor.ts +++ b/packages/forms/src/directives/checkbox_value_accessor.ts @@ -47,51 +47,11 @@ export const CHECKBOX_VALUE_ACCESSOR: any = { }) export class CheckboxControlValueAccessor extends BuiltInControlValueAccessor implements ControlValueAccessor { - /** - * The registered callback function called when a change event occurs on the input element. - * @nodoc - */ - onChange = (_: any) => {}; - - /** - * The registered callback function called when a blur event occurs on the input element. - * @nodoc - */ - onTouched = () => {}; - - constructor(private _renderer: Renderer2, private _elementRef: ElementRef) { - super(); - } - /** * Sets the "checked" property on the input element. * @nodoc */ writeValue(value: any): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'checked', value); - } - - /** - * Registers a function called when the control value changes. - * @nodoc - */ - registerOnChange(fn: (_: any) => {}): void { - this.onChange = fn; - } - - /** - * Registers a function called when the control is touched. - * @nodoc - */ - registerOnTouched(fn: () => {}): void { - this.onTouched = fn; - } - - /** - * Sets the "disabled" property on the input element. - * @nodoc - */ - setDisabledState(isDisabled: boolean): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled); + this.setProperty('checked', value); } } diff --git a/packages/forms/src/directives/control_value_accessor.ts b/packages/forms/src/directives/control_value_accessor.ts index 9c150ee2ea..228c666196 100644 --- a/packages/forms/src/directives/control_value_accessor.ts +++ b/packages/forms/src/directives/control_value_accessor.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {InjectionToken} from '@angular/core'; +import {Directive, ElementRef, InjectionToken, Renderer2} from '@angular/core'; /** * @description @@ -132,13 +132,75 @@ export interface ControlValueAccessor { } /** - * Base class for all built-in ControlValueAccessor classes. We use this class to distinguish - * between built-in and custom CVAs, so that Forms logic can recognize built-in CVAs and treat - * custom ones with higher priority (when both built-in and custom CVAs are present). + * Base class for all ControlValueAccessor classes defined in Forms package. + * Contains common logic and utility functions. + * * Note: this is an *internal-only* class and should not be extended or used directly in * applications code. */ -export class BuiltInControlValueAccessor {} +@Directive() +export class BaseControlValueAccessor { + /** + * The registered callback function called when a change or input event occurs on the input + * element. + * @nodoc + */ + onChange = (_: any) => {}; + + /** + * The registered callback function called when a blur event occurs on the input element. + * @nodoc + */ + onTouched = () => {}; + + constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {} + + /** + * Helper method that sets a property on a target element using the current Renderer + * implementation. + * @nodoc + */ + protected setProperty(key: string, value: any): void { + this._renderer.setProperty(this._elementRef.nativeElement, key, value); + } + + /** + * Registers a function called when the control is touched. + * @nodoc + */ + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + /** + * Registers a function called when the control value changes. + * @nodoc + */ + registerOnChange(fn: (_: any) => {}): void { + this.onChange = fn; + } + + /** + * Sets the "disabled" property on the range input element. + * @nodoc + */ + setDisabledState(isDisabled: boolean): void { + this.setProperty('disabled', isDisabled); + } +} + +/** + * Base class for all built-in ControlValueAccessor classes (except DefaultValueAccessor, which is + * used in case no other CVAs can be found). We use this class to distinguish between default CVA, + * built-in CVAs and custom CVAs, so that Forms logic can recognize built-in CVAs and treat custom + * ones with higher priority (when both built-in and custom CVAs are present). + * + * Note: this is an *internal-only* class and should not be extended or used directly in + * applications code. + */ +@Directive() +export class BuiltInControlValueAccessor extends BaseControlValueAccessor { +} /** * Used to provide a `ControlValueAccessor` for form controls. diff --git a/packages/forms/src/directives/default_value_accessor.ts b/packages/forms/src/directives/default_value_accessor.ts index de1883b45d..2c0fc9f132 100644 --- a/packages/forms/src/directives/default_value_accessor.ts +++ b/packages/forms/src/directives/default_value_accessor.ts @@ -9,7 +9,7 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {Directive, ElementRef, forwardRef, Inject, InjectionToken, Optional, Renderer2} from '@angular/core'; -import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; +import {BaseControlValueAccessor, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; export const DEFAULT_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, @@ -83,25 +83,14 @@ export const COMPOSITION_BUFFER_MODE = new InjectionToken('CompositionE }, providers: [DEFAULT_VALUE_ACCESSOR] }) -export class DefaultValueAccessor implements ControlValueAccessor { - /** - * The registered callback function called when an input event occurs on the input element. - * @nodoc - */ - onChange = (_: any) => {}; - - /** - * The registered callback function called when a blur event occurs on the input element. - * @nodoc - */ - onTouched = () => {}; - +export class DefaultValueAccessor extends BaseControlValueAccessor implements ControlValueAccessor { /** Whether the user is creating a composition string (IME events). */ private _composing = false; constructor( - private _renderer: Renderer2, private _elementRef: ElementRef, + renderer: Renderer2, elementRef: ElementRef, @Optional() @Inject(COMPOSITION_BUFFER_MODE) private _compositionMode: boolean) { + super(renderer, elementRef); if (this._compositionMode == null) { this._compositionMode = !_isAndroid(); } @@ -113,31 +102,7 @@ export class DefaultValueAccessor implements ControlValueAccessor { */ writeValue(value: any): void { const normalizedValue = value == null ? '' : value; - this._renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue); - } - - /** - * Registers a function called when the control value changes. - * @nodoc - */ - registerOnChange(fn: (_: any) => void): void { - this.onChange = fn; - } - - /** - * Registers a function called when the control is touched. - * @nodoc - */ - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - /** - * Sets the "disabled" property on the input element. - * @nodoc - */ - setDisabledState(isDisabled: boolean): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled); + this.setProperty('value', normalizedValue); } /** @internal */ diff --git a/packages/forms/src/directives/number_value_accessor.ts b/packages/forms/src/directives/number_value_accessor.ts index a90eda5d8f..8164453746 100644 --- a/packages/forms/src/directives/number_value_accessor.ts +++ b/packages/forms/src/directives/number_value_accessor.ts @@ -48,23 +48,6 @@ export const NUMBER_VALUE_ACCESSOR: any = { }) export class NumberValueAccessor extends BuiltInControlValueAccessor implements ControlValueAccessor { - /** - * The registered callback function called when a change or input event occurs on the input - * element. - * @nodoc - */ - onChange = (_: any) => {}; - - /** - * The registered callback function called when a blur event occurs on the input element. - * @nodoc - */ - onTouched = () => {}; - - constructor(private _renderer: Renderer2, private _elementRef: ElementRef) { - super(); - } - /** * Sets the "value" property on the input element. * @nodoc @@ -72,7 +55,7 @@ export class NumberValueAccessor extends BuiltInControlValueAccessor implements writeValue(value: number): void { // The value needs to be normalized for IE9, otherwise it is set to 'null' when null const normalizedValue = value == null ? '' : value; - this._renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue); + this.setProperty('value', normalizedValue); } /** @@ -84,20 +67,4 @@ export class NumberValueAccessor extends BuiltInControlValueAccessor implements fn(value == '' ? null : parseFloat(value)); }; } - - /** - * Registers a function called when the control is touched. - * @nodoc - */ - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - /** - * Sets the "disabled" property on the input element. - * @nodoc - */ - setDisabledState(isDisabled: boolean): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled); - } } diff --git a/packages/forms/src/directives/radio_control_value_accessor.ts b/packages/forms/src/directives/radio_control_value_accessor.ts index f0b0e2e92f..0820e588ac 100644 --- a/packages/forms/src/directives/radio_control_value_accessor.ts +++ b/packages/forms/src/directives/radio_control_value_accessor.ts @@ -124,16 +124,13 @@ export class RadioControlValueAccessor extends BuiltInControlValueAccessor imple /** * The registered callback function called when a change event occurs on the input element. + * Note: we declare `onChange` here (also used as host listener) as a function with no arguments + * to override the `onChange` function (which expects 1 argument) in the parent + * `BaseControlValueAccessor` class. * @nodoc */ onChange = () => {}; - /** - * The registered callback function called when a blur event occurs on the input element. - * @nodoc - */ - onTouched = () => {}; - /** * @description * Tracks the name of the radio input element. @@ -156,9 +153,9 @@ export class RadioControlValueAccessor extends BuiltInControlValueAccessor imple @Input() value: any; constructor( - private _renderer: Renderer2, private _elementRef: ElementRef, - private _registry: RadioControlRegistry, private _injector: Injector) { - super(); + renderer: Renderer2, elementRef: ElementRef, private _registry: RadioControlRegistry, + private _injector: Injector) { + super(renderer, elementRef); } /** @nodoc */ @@ -179,7 +176,7 @@ export class RadioControlValueAccessor extends BuiltInControlValueAccessor imple */ writeValue(value: any): void { this._state = value === this.value; - this._renderer.setProperty(this._elementRef.nativeElement, 'checked', this._state); + this.setProperty('checked', this._state); } /** @@ -203,22 +200,6 @@ export class RadioControlValueAccessor extends BuiltInControlValueAccessor imple this.writeValue(value); } - /** - * Registers a function called when the control is touched. - * @nodoc - */ - registerOnTouched(fn: () => {}): void { - this.onTouched = fn; - } - - /** - * Sets the "disabled" property on the input element. - * @nodoc - */ - setDisabledState(isDisabled: boolean): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled); - } - private _checkName(): void { if (this.name && this.formControlName && this.name !== this.formControlName && (typeof ngDevMode === 'undefined' || ngDevMode)) { diff --git a/packages/forms/src/directives/range_value_accessor.ts b/packages/forms/src/directives/range_value_accessor.ts index 8cd487b1b5..5c74cba682 100644 --- a/packages/forms/src/directives/range_value_accessor.ts +++ b/packages/forms/src/directives/range_value_accessor.ts @@ -52,29 +52,12 @@ export const RANGE_VALUE_ACCESSOR: StaticProvider = { }) export class RangeValueAccessor extends BuiltInControlValueAccessor implements ControlValueAccessor { - /** - * The registered callback function called when a change or input event occurs on the input - * element. - * @nodoc - */ - onChange = (_: any) => {}; - - /** - * The registered callback function called when a blur event occurs on the input element. - * @nodoc - */ - onTouched = () => {}; - - constructor(private _renderer: Renderer2, private _elementRef: ElementRef) { - super(); - } - /** * Sets the "value" property on the input element. * @nodoc */ writeValue(value: any): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'value', parseFloat(value)); + this.setProperty('value', parseFloat(value)); } /** @@ -86,20 +69,4 @@ export class RangeValueAccessor extends BuiltInControlValueAccessor implements fn(value == '' ? null : parseFloat(value)); }; } - - /** - * Registers a function called when the control is touched. - * @nodoc - */ - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - /** - * Sets the "disabled" property on the range input element. - * @nodoc - */ - setDisabledState(isDisabled: boolean): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled); - } } diff --git a/packages/forms/src/directives/select_control_value_accessor.ts b/packages/forms/src/directives/select_control_value_accessor.ts index d1c23eb1f4..ee6c4cca40 100644 --- a/packages/forms/src/directives/select_control_value_accessor.ts +++ b/packages/forms/src/directives/select_control_value_accessor.ts @@ -99,18 +99,6 @@ export class SelectControlValueAccessor extends BuiltInControlValueAccessor impl /** @internal */ _idCounter: number = 0; - /** - * The registered callback function called when a change event occurs on the input element. - * @nodoc - */ - onChange = (_: any) => {}; - - /** - * The registered callback function called when a blur event occurs on the input element. - * @nodoc - */ - onTouched = () => {}; - /** * @description * Tracks the option comparison algorithm for tracking identities when @@ -126,10 +114,6 @@ export class SelectControlValueAccessor extends BuiltInControlValueAccessor impl private _compareWith: (o1: any, o2: any) => boolean = Object.is; - constructor(private _renderer: Renderer2, private _elementRef: ElementRef) { - super(); - } - /** * Sets the "value" property on the input element. The "selectedIndex" * property is also set if an ID is provided on the option element. @@ -139,10 +123,10 @@ export class SelectControlValueAccessor extends BuiltInControlValueAccessor impl this.value = value; const id: string|null = this._getOptionId(value); if (id == null) { - this._renderer.setProperty(this._elementRef.nativeElement, 'selectedIndex', -1); + this.setProperty('selectedIndex', -1); } const valueString = _buildValueString(id, value); - this._renderer.setProperty(this._elementRef.nativeElement, 'value', valueString); + this.setProperty('value', valueString); } /** @@ -156,22 +140,6 @@ export class SelectControlValueAccessor extends BuiltInControlValueAccessor impl }; } - /** - * Registers a function called when the control is touched. - * @nodoc - */ - registerOnTouched(fn: () => any): void { - this.onTouched = fn; - } - - /** - * Sets the "disabled" property on the select input element. - * @nodoc - */ - setDisabledState(isDisabled: boolean): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled); - } - /** @internal */ _registerOption(): string { return (this._idCounter++).toString(); diff --git a/packages/forms/src/directives/select_multiple_control_value_accessor.ts b/packages/forms/src/directives/select_multiple_control_value_accessor.ts index 1af649c777..0adf312cf7 100644 --- a/packages/forms/src/directives/select_multiple_control_value_accessor.ts +++ b/packages/forms/src/directives/select_multiple_control_value_accessor.ts @@ -95,18 +95,6 @@ export class SelectMultipleControlValueAccessor extends BuiltInControlValueAcces /** @internal */ _idCounter: number = 0; - /** - * The registered callback function called when a change event occurs on the input element. - * @nodoc - */ - onChange = (_: any) => {}; - - /** - * The registered callback function called when a blur event occurs on the input element. - * @nodoc - */ - onTouched = () => {}; - /** * @description * Tracks the option comparison algorithm for tracking identities when @@ -122,10 +110,6 @@ export class SelectMultipleControlValueAccessor extends BuiltInControlValueAcces private _compareWith: (o1: any, o2: any) => boolean = Object.is; - constructor(private _renderer: Renderer2, private _elementRef: ElementRef) { - super(); - } - /** * Sets the "value" property on one or of more of the select's options. * @nodoc @@ -179,22 +163,6 @@ export class SelectMultipleControlValueAccessor extends BuiltInControlValueAcces }; } - /** - * Registers a function called when the control is touched. - * @nodoc - */ - registerOnTouched(fn: () => any): void { - this.onTouched = fn; - } - - /** - * Sets the "disabled" property on the select input element. - * @nodoc - */ - setDisabledState(isDisabled: boolean): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled); - } - /** @internal */ _registerOption(value: ɵNgSelectMultipleOption): string { const id: string = (this._idCounter++).toString();