Skip to content

Commit

Permalink
fixup! perf(forms): make built-in ControlValueAccessors more tree-sha…
Browse files Browse the repository at this point in the history
…kable
  • Loading branch information
AndrewKushnir committed Mar 11, 2021
1 parent f13bb23 commit 075d210
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 64 deletions.
15 changes: 6 additions & 9 deletions packages/forms/src/directives/checkbox_value_accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Directive, ElementRef, forwardRef, Renderer2} from '@angular/core';

import {BUILTIN_ACCESSOR_MARKER, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {BuiltInControlValueAccessor, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';

export const CHECKBOX_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
Expand Down Expand Up @@ -45,13 +45,8 @@ export const CHECKBOX_VALUE_ACCESSOR: any = {
host: {'(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()'},
providers: [CHECKBOX_VALUE_ACCESSOR]
})
export class CheckboxControlValueAccessor implements ControlValueAccessor {
/**
* Internal-only field that indicates that this a built-in ControlValueAccessor.
* @internal
*/
static[BUILTIN_ACCESSOR_MARKER] = true;

export class CheckboxControlValueAccessor extends BuiltInControlValueAccessor implements
ControlValueAccessor {
/**
* The registered callback function called when a change event occurs on the input element.
* @nodoc
Expand All @@ -64,7 +59,9 @@ export class CheckboxControlValueAccessor implements ControlValueAccessor {
*/
onTouched = () => {};

constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {
super();
}

/**
* Sets the "checked" property on the input element.
Expand Down
18 changes: 10 additions & 8 deletions packages/forms/src/directives/control_value_accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@ export interface ControlValueAccessor {
setDisabledState?(isDisabled: boolean): void;
}

/**
* 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).
* Note: this is an *internal-only* class and should not be extended or used directly in
* applications code.
*/
export class BuiltInControlValueAccessor {}

/**
* Used to provide a `ControlValueAccessor` for form controls.
*
Expand All @@ -139,11 +148,4 @@ export interface ControlValueAccessor {
* @publicApi
*/
export const NG_VALUE_ACCESSOR =
new InjectionToken<ReadonlyArray<ControlValueAccessor>>('NgValueAccessor');

/**
* Name of the internal-only field that is present on all built-in ControlValueAccessor (CVA)
* classes. This is needed to make all standard CVAs tree-shakable (to avoid direct references to
* specific classes).
*/
export const BUILTIN_ACCESSOR_MARKER = '__ngBuiltinCVA__';
new InjectionToken<ReadonlyArray<ControlValueAccessor>>('NgValueAccessor');
15 changes: 6 additions & 9 deletions packages/forms/src/directives/number_value_accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Directive, ElementRef, forwardRef, Renderer2} from '@angular/core';

import {BUILTIN_ACCESSOR_MARKER, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {BuiltInControlValueAccessor, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';

export const NUMBER_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
Expand Down Expand Up @@ -46,13 +46,8 @@ export const NUMBER_VALUE_ACCESSOR: any = {
host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
providers: [NUMBER_VALUE_ACCESSOR]
})
export class NumberValueAccessor implements ControlValueAccessor {
/**
* Internal-only field that indicates that this a built-in ControlValueAccessor.
* @internal
*/
static[BUILTIN_ACCESSOR_MARKER] = true;

export class NumberValueAccessor extends BuiltInControlValueAccessor implements
ControlValueAccessor {
/**
* The registered callback function called when a change or input event occurs on the input
* element.
Expand All @@ -66,7 +61,9 @@ export class NumberValueAccessor implements ControlValueAccessor {
*/
onTouched = () => {};

constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {
super();
}

/**
* Sets the "value" property on the input element.
Expand Down
15 changes: 6 additions & 9 deletions packages/forms/src/directives/radio_control_value_accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Directive, ElementRef, forwardRef, Injectable, Injector, Input, OnDestroy, OnInit, Renderer2} from '@angular/core';

import {BUILTIN_ACCESSOR_MARKER, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {BuiltInControlValueAccessor, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {NgControl} from './ng_control';

export const RADIO_VALUE_ACCESSOR: any = {
Expand Down Expand Up @@ -100,13 +100,8 @@ export class RadioControlRegistry {
host: {'(change)': 'onChange()', '(blur)': 'onTouched()'},
providers: [RADIO_VALUE_ACCESSOR]
})
export class RadioControlValueAccessor implements ControlValueAccessor, OnDestroy, OnInit {
/**
* Internal-only field that indicates that this a built-in ControlValueAccessor.
* @internal
*/
static[BUILTIN_ACCESSOR_MARKER] = true;

export class RadioControlValueAccessor extends BuiltInControlValueAccessor implements
ControlValueAccessor, OnDestroy, OnInit {
/** @internal */
// TODO(issue/24571): remove '!'.
_state!: boolean;
Expand Down Expand Up @@ -152,7 +147,9 @@ export class RadioControlValueAccessor implements ControlValueAccessor, OnDestro

constructor(
private _renderer: Renderer2, private _elementRef: ElementRef,
private _registry: RadioControlRegistry, private _injector: Injector) {}
private _registry: RadioControlRegistry, private _injector: Injector) {
super();
}

/** @nodoc */
ngOnInit(): void {
Expand Down
15 changes: 6 additions & 9 deletions packages/forms/src/directives/range_value_accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Directive, ElementRef, forwardRef, Renderer2, StaticProvider} from '@angular/core';

import {BUILTIN_ACCESSOR_MARKER, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {BuiltInControlValueAccessor, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';

export const RANGE_VALUE_ACCESSOR: StaticProvider = {
provide: NG_VALUE_ACCESSOR,
Expand Down Expand Up @@ -50,13 +50,8 @@ export const RANGE_VALUE_ACCESSOR: StaticProvider = {
},
providers: [RANGE_VALUE_ACCESSOR]
})
export class RangeValueAccessor implements ControlValueAccessor {
/**
* Internal-only field that indicates that this a built-in ControlValueAccessor.
* @internal
*/
static[BUILTIN_ACCESSOR_MARKER] = true;

export class RangeValueAccessor extends BuiltInControlValueAccessor implements
ControlValueAccessor {
/**
* The registered callback function called when a change or input event occurs on the input
* element.
Expand All @@ -70,7 +65,9 @@ export class RangeValueAccessor implements ControlValueAccessor {
*/
onTouched = () => {};

constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {
super();
}

/**
* Sets the "value" property on the input element.
Expand Down
15 changes: 6 additions & 9 deletions packages/forms/src/directives/select_control_value_accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider} from '@angular/core';

import {BUILTIN_ACCESSOR_MARKER, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {BuiltInControlValueAccessor, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';

export const SELECT_VALUE_ACCESSOR: StaticProvider = {
provide: NG_VALUE_ACCESSOR,
Expand Down Expand Up @@ -88,13 +88,8 @@ function _extractId(valueString: string): string {
host: {'(change)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
providers: [SELECT_VALUE_ACCESSOR]
})
export class SelectControlValueAccessor implements ControlValueAccessor {
/**
* Internal-only field that indicates that this a built-in ControlValueAccessor.
* @internal
*/
static[BUILTIN_ACCESSOR_MARKER] = true;

export class SelectControlValueAccessor extends BuiltInControlValueAccessor implements
ControlValueAccessor {
/** @nodoc */
value: any;

Expand Down Expand Up @@ -131,7 +126,9 @@ export class SelectControlValueAccessor implements ControlValueAccessor {

private _compareWith: (o1: any, o2: any) => boolean = Object.is;

constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {
super();
}

/**
* Sets the "value" property on the input element. The "selectedIndex"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider} from '@angular/core';

import {BUILTIN_ACCESSOR_MARKER, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {BuiltInControlValueAccessor, ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';

export const SELECT_MULTIPLE_VALUE_ACCESSOR: StaticProvider = {
provide: NG_VALUE_ACCESSOR,
Expand Down Expand Up @@ -81,13 +81,8 @@ abstract class HTMLCollection {
host: {'(change)': 'onChange($event.target)', '(blur)': 'onTouched()'},
providers: [SELECT_MULTIPLE_VALUE_ACCESSOR]
})
export class SelectMultipleControlValueAccessor implements ControlValueAccessor {
/**
* Internal-only field that indicates that this a built-in ControlValueAccessor.
* @internal
*/
static[BUILTIN_ACCESSOR_MARKER] = true;

export class SelectMultipleControlValueAccessor extends BuiltInControlValueAccessor implements
ControlValueAccessor {
/**
* The current value.
* @nodoc
Expand Down Expand Up @@ -127,7 +122,9 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor

private _compareWith: (o1: any, o2: any) => boolean = Object.is;

constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {
super();
}

/**
* Sets the "value" property on one or of more of the select's options.
Expand Down
6 changes: 4 additions & 2 deletions packages/forms/src/directives/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {getControlAsyncValidators, getControlValidators, mergeValidators} from '
import {AbstractControlDirective} from './abstract_control_directive';
import {AbstractFormGroupDirective} from './abstract_form_group_directive';
import {ControlContainer} from './control_container';
import {BUILTIN_ACCESSOR_MARKER, ControlValueAccessor} from './control_value_accessor';
import {BuiltInControlValueAccessor, ControlValueAccessor} from './control_value_accessor';
import {DefaultValueAccessor} from './default_value_accessor';
import {NgControl} from './ng_control';
import {FormArrayName} from './reactive_directives/form_group_name';
Expand Down Expand Up @@ -304,7 +304,9 @@ export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any)
}

export function isBuiltInAccessor(valueAccessor: ControlValueAccessor): boolean {
return valueAccessor.constructor.hasOwnProperty(BUILTIN_ACCESSOR_MARKER);
// Check if a given value accessor is an instance of a class that directly extends
// `BuiltInControlValueAccessor` one.
return Object.getPrototypeOf(valueAccessor.constructor) === BuiltInControlValueAccessor;
}

export function syncPendingControls(form: FormGroup, directives: NgControl[]): void {
Expand Down

0 comments on commit 075d210

Please sign in to comment.