docs(forms): update API reference for value accessors (#26946)

PR Close #26946
This commit is contained in:
Brandon Roberts 2018-11-01 15:23:01 -05:00 committed by Andrew Kushnir
parent e5c9f7a507
commit 99c5db1fb1
7 changed files with 439 additions and 99 deletions

View File

@ -17,17 +17,26 @@ export const CHECKBOX_VALUE_ACCESSOR: any = {
};
/**
* The accessor for writing a value and listening to changes on a checkbox input element.
* @description
* A `ControlValueAccessor` for writing a value and listening to changes on a checkbox input
* element.
*
* @usageNotes
* ### Example
*
* ```
* <input type="checkbox" name="rememberLogin" ngModel>
* ### Using a checkbox with a reactive form.
*
* The following example shows how to use a checkbox with a reactive form.
*
* ```ts
* const rememberLoginControl = new FormControl();
* ```
*
* ```
* <input type="checkbox" [formControl]="rememberLoginControl">
* ```
*
* @ngModule FormsModule
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
* @publicApi
*/
@Directive({
@ -37,17 +46,50 @@ export const CHECKBOX_VALUE_ACCESSOR: any = {
providers: [CHECKBOX_VALUE_ACCESSOR]
})
export class CheckboxControlValueAccessor implements ControlValueAccessor {
/**
* @description
* The registered callback function called when a change event occurs on the input element.
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
*/
onTouched = () => {};
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
/**
* Sets the "checked" property on the input element.
*
* @param value The checked value
*/
writeValue(value: any): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'checked', value);
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
*/
registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; }
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
*/
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
/**
* Sets the "disabled" property on the input element.
*
* @param isDisabled The disabled value
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}

View File

@ -32,18 +32,28 @@ function _isAndroid(): boolean {
export const COMPOSITION_BUFFER_MODE = new InjectionToken<boolean>('CompositionEventMode');
/**
* The default accessor for writing a value and listening to changes that is used by the
* `NgModel`, `FormControlDirective`, and `FormControlName` directives.
* @description
* The default `ControlValueAccessor` for writing a value and listening to changes on input
* elements. The accessor is used by the `FormControlDirective`, `FormControlName`, and
* `NgModel` directives.
*
* @usageNotes
* ### Example
*
* ```
* <input type="text" name="searchQuery" ngModel>
* ### Using the default value accessor
*
* The following example shows how to use an input element that activates the default value accessor
* (in this case, a text field).
*
* ```ts
* const firstNameControl = new FormControl();
* ```
*
* ```
* <input type="text" [formControl]="firstNameControl">
* ```
*
* @ngModule FormsModule
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
* @publicApi
*/
@Directive({
@ -61,7 +71,16 @@ export const COMPOSITION_BUFFER_MODE = new InjectionToken<boolean>('CompositionE
providers: [DEFAULT_VALUE_ACCESSOR]
})
export class DefaultValueAccessor implements ControlValueAccessor {
/**
* @description
* The registered callback function called when an input event occurs on the input element.
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
*/
onTouched = () => {};
/** Whether the user is creating a composition string (IME events). */
@ -75,14 +94,37 @@ export class DefaultValueAccessor implements ControlValueAccessor {
}
}
/**
* Sets the "value" property on the input element.
*
* @param value The checked value
*/
writeValue(value: any): void {
const normalizedValue = value == null ? '' : value;
this._renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue);
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
*/
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
*/
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
/**
* Sets the "disabled" property on the input element.
*
* @param isDisabled The disabled value
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}

View File

@ -17,18 +17,27 @@ export const NUMBER_VALUE_ACCESSOR: any = {
};
/**
* The accessor for writing a number value and listening to changes that is used by the
* `NgModel`, `FormControlDirective`, and `FormControlName` directives.
* @description
* The `ControlValueAccessor` for writing a number value and listening to number input changes.
* The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
* directives.
*
* @usageNotes
* ### Example
*
* ```
* <input type="number" [(ngModel)]="age">
* ### Using a number input with a reactive form.
*
* The following example shows how to use a number input with a reactive form.
*
* ```ts
* const totalCountControl = new FormControl();
* ```
*
* ```
* <input type="number" [formControl]="totalCountControl">
* ```
*
* @ngModule FormsModule
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
*/
@Directive({
selector:
@ -41,22 +50,55 @@ export const NUMBER_VALUE_ACCESSOR: any = {
providers: [NUMBER_VALUE_ACCESSOR]
})
export class NumberValueAccessor implements ControlValueAccessor {
/**
* @description
* The registered callback function called when a change or input event occurs on the input
* element.
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
*/
onTouched = () => {};
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
/**
* Sets the "value" property on the input element.
*
* @param value The checked value
*/
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);
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
*/
registerOnChange(fn: (_: number|null) => void): void {
this.onChange = (value) => { fn(value == '' ? null : parseFloat(value)); };
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
*/
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
/**
* Sets the "disabled" property on the input element.
*
* @param isDisabled The disabled value
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}

View File

@ -18,16 +18,25 @@ export const RADIO_VALUE_ACCESSOR: any = {
};
/**
* Internal class used by Angular to uncheck radio buttons with the matching name.
* @description
* Class used by Angular to track radio buttons. For internal use only.
*/
@Injectable()
export class RadioControlRegistry {
private _accessors: any[] = [];
/**
* @description
* Adds a control to the internal registry. For internal use only.
*/
add(control: NgControl, accessor: RadioControlValueAccessor) {
this._accessors.push([control, accessor]);
}
/**
* @description
* Removes a control from the internal registry. For internal use only.
*/
remove(accessor: RadioControlValueAccessor) {
for (let i = this._accessors.length - 1; i >= 0; --i) {
if (this._accessors[i][1] === accessor) {
@ -37,6 +46,10 @@ export class RadioControlRegistry {
}
}
/**
* @description
* Selects a radio button. For internal use only.
*/
select(accessor: RadioControlValueAccessor) {
this._accessors.forEach((c) => {
if (this._isSameGroup(c, accessor) && c[1] !== accessor) {
@ -56,32 +69,22 @@ export class RadioControlRegistry {
/**
* @description
*
* Writes radio control values and listens to radio control changes.
*
* Used by `NgModel`, `FormControlDirective`, and `FormControlName`
* to keep the view synced with the `FormControl` model.
*
* If you have imported the `FormsModule` or the `ReactiveFormsModule`, this
* value accessor will be active on any radio control that has a form directive. You do
* **not** need to add a special selector to activate it.
* The `ControlValueAccessor` for writing radio control values and listening to radio control
* changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
* `NgModel` directives.
*
* @usageNotes
* ### How to use radio buttons with form directives
*
* To use radio buttons in a template-driven form, you'll want to ensure that radio buttons
* in the same group have the same `name` attribute. Radio buttons with different `name`
* attributes do not affect each other.
* ### Using radio buttons with reactive form directives
*
* {@example forms/ts/radioButtons/radio_button_example.ts region='TemplateDriven'}
*
* When using radio buttons in a reactive form, radio buttons in the same group should have the
* same `formControlName`. You can also add a `name` attribute, but it's optional.
* The follow example shows how to use radio buttons in a reactive form. When using radio buttons in
* a reactive form, radio buttons in the same group should have the same `formControlName`.
* Providing a `name` attribute is optional.
*
* {@example forms/ts/reactiveRadioButtons/reactive_radio_button_example.ts region='Reactive'}
*
* @ngModule FormsModule
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
* @publicApi
*/
@Directive({
@ -101,32 +104,81 @@ export class RadioControlValueAccessor implements ControlValueAccessor,
/** @internal */
// TODO(issue/24571): remove '!'.
_fn !: Function;
/**
* @description
* The registered callback function called when a change event occurs on the input element.
*/
onChange = () => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
*/
onTouched = () => {};
/**
* @description
* Tracks the name of the radio input element.
*/
// TODO(issue/24571): remove '!'.
@Input() name !: string;
/**
* @description
* Tracks the name of the `FormControl` bound to the directive. The name corresponds
* to a key in the parent `FormGroup` or `FormArray`.
*/
// TODO(issue/24571): remove '!'.
@Input() formControlName !: string;
/**
* @description
* Tracks the value of the radio input element
*/
@Input() value: any;
constructor(
private _renderer: Renderer2, private _elementRef: ElementRef,
private _registry: RadioControlRegistry, private _injector: Injector) {}
/**
* @description
* A lifecycle method called when the directive is initialized. For internal use only.
*
* @param changes A object of key/value pairs for the set of changed inputs.
*/
ngOnInit(): void {
this._control = this._injector.get(NgControl);
this._checkName();
this._registry.add(this._control, this);
}
/**
* @description
* Lifecycle method called before the directive's instance is destroyed. For internal use only.
*
* @param changes A object of key/value pairs for the set of changed inputs.
*/
ngOnDestroy(): void { this._registry.remove(this); }
/**
* @description
* Sets the "checked" property value on the radio input element.
*
* @param value The checked value
*/
writeValue(value: any): void {
this._state = value === this.value;
this._renderer.setProperty(this._elementRef.nativeElement, 'checked', this._state);
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
*/
registerOnChange(fn: (_: any) => {}): void {
this._fn = fn;
this.onChange = () => {
@ -135,10 +187,26 @@ export class RadioControlValueAccessor implements ControlValueAccessor,
};
}
/**
* Sets the "value" on the radio input element and unchecks it.
*
* @param value
*/
fireUncheck(value: any): void { this.writeValue(value); }
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
*/
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
/**
* Sets the "disabled" property on the input element.
*
* @param isDisabled The disabled value
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}

View File

@ -17,18 +17,27 @@ export const RANGE_VALUE_ACCESSOR: StaticProvider = {
};
/**
* The accessor for writing a range value and listening to changes that is used by the
* `NgModel`, `FormControlDirective`, and `FormControlName` directives.
* @description
* The `ControlValueAccessor` for writing a range value and listening to range input changes.
* The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
* directives.
*
* @usageNotes
* ### Example
*
* ```
* <input type="range" [(ngModel)]="age" >
* ### Using a range input with a reactive form
*
* The following example shows how to use a range input with a reactive form.
*
* ```ts
* const ageControl = new FormControl();
* ```
*
* ```
* <input type="range" [formControl]="ageControl">
* ```
*
* @ngModule FormsModule
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
*/
@Directive({
selector:
@ -41,21 +50,53 @@ export const RANGE_VALUE_ACCESSOR: StaticProvider = {
providers: [RANGE_VALUE_ACCESSOR]
})
export class RangeValueAccessor implements ControlValueAccessor {
/**
* @description
* The registered callback function called when a change or input event occurs on the input
* element.
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
*/
onTouched = () => {};
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
/**
* Sets the "value" property on the input element.
*
* @param value The checked value
*/
writeValue(value: any): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'value', parseFloat(value));
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
*/
registerOnChange(fn: (_: number|null) => void): void {
this.onChange = (value) => { fn(value == '' ? null : parseFloat(value)); };
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
*/
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
/**
* Sets the "disabled" property on the range input element.
*
* @param isDisabled The disabled value
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}

View File

@ -28,35 +28,26 @@ function _extractId(valueString: string): string {
/**
* @description
*
* Writes values and listens to changes on a select element.
*
* Used by `NgModel`, `FormControlDirective`, and `FormControlName`
* to keep the view synced with the `FormControl` model.
*
* If you have imported the `FormsModule` or the `ReactiveFormsModule`, this
* value accessor will be active on any select control that has a form directive. You do
* **not** need to add a special selector to activate it.
* The `ControlValueAccessor` for writing select control values and listening to select control
* changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
* `NgModel` directives.
*
* @usageNotes
* ### How to use select controls with form directives
*
* ### Using select controls in a reactive form
*
* The following examples show how to use a select control in a reactive form.
*
* {@example forms/ts/reactiveSelectControl/reactive_select_control_example.ts region='Component'}
*
* ### Using select controls in a template-driven form
*
* To use a select in a template-driven form, simply add an `ngModel` and a `name`
* attribute to the main `<select>` tag.
*
* If your option values are simple strings, you can bind to the normal `value` property
* on the option. If your option values happen to be objects (and you'd like to save the
* selection in your form as an object), use `ngValue` instead:
*
* {@example forms/ts/selectControl/select_control_example.ts region='Component'}
*
* In reactive forms, you'll also want to add your form directive (`formControlName` or
* `formControl`) on the main `<select>` tag. Like in the former example, you have the
* choice of binding to the `value` or `ngValue` property on the select's options.
*
* {@example forms/ts/reactiveSelectControl/reactive_select_control_example.ts region='Component'}
*
* ### Caveat: Option selection
* ### Customizing option selection
*
* Angular uses object identity to select option. It's possible for the identities of items
* to change while the data does not. This can happen, for example, if the items are produced
@ -67,10 +58,12 @@ function _extractId(valueString: string): string {
* `compareWith` takes a **function** which has two arguments: `option1` and `option2`.
* If `compareWith` is given, Angular selects option by the return value of the function.
*
* ### Syntax
* ```ts
* const selectedCountriesControl = new FormControl();
* ```
*
* ```
* <select [compareWith]="compareFn" [(ngModel)]="selectedCountries">
* <select [compareWith]="compareFn" [formControl]="selectedCountriesControl">
* <option *ngFor="let country of countries" [ngValue]="country">
* {{country.name}}
* </option>
@ -81,13 +74,13 @@ function _extractId(valueString: string): string {
* }
* ```
*
* Note: We listen to the 'change' event because 'input' events aren't fired
* **Note:** We listen to the 'change' event because 'input' events aren't fired
* for selects in Firefox and IE:
* https://bugzilla.mozilla.org/show_bug.cgi?id=1024350
* https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4660045/
*
* @ngModule FormsModule
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
* @publicApi
*/
@Directive({
@ -103,9 +96,23 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
/** @internal */
_idCounter: number = 0;
/**
* @description
* The registered callback function called when a change event occurs on the input element.
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
*/
onTouched = () => {};
/**
* @description
* Tracks the option comparison algorithm for tracking identities when
* checking for changes.
*/
@Input()
set compareWith(fn: (o1: any, o2: any) => boolean) {
if (typeof fn !== 'function') {
@ -118,6 +125,12 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
/**
* Sets the "value" property on the input element. The "selectedIndex"
* property is also set if an ID is provided on the option element.
*
* @param value The checked value
*/
writeValue(value: any): void {
this.value = value;
const id: string|null = this._getOptionId(value);
@ -128,14 +141,32 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
this._renderer.setProperty(this._elementRef.nativeElement, 'value', valueString);
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
*/
registerOnChange(fn: (value: any) => any): void {
this.onChange = (valueString: string) => {
this.value = this._getOptionValue(valueString);
fn(this.value);
};
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
*/
registerOnTouched(fn: () => any): void { this.onTouched = fn; }
/**
* Sets the "disabled" property on the select input element.
*
* @param isDisabled The disabled value
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}
@ -160,17 +191,20 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
/**
* @description
*
* Marks `<option>` as dynamic, so Angular can be notified when options change.
*
* See docs for `SelectControlValueAccessor` for usage examples.
* @see `SelectControlValueAccessor`
*
* @ngModule FormsModule
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
* @publicApi
*/
@Directive({selector: 'option'})
export class NgSelectOption implements OnDestroy {
/**
* @description
* ID of the option element
*/
// TODO(issue/24571): remove '!'.
id !: string;
@ -180,6 +214,11 @@ export class NgSelectOption implements OnDestroy {
if (this._select) this.id = this._select._registerOption();
}
/**
* @description
* Tracks the value bound to the option element. Unlike the value binding,
* ngValue supports binding to objects.
*/
@Input('ngValue')
set ngValue(value: any) {
if (this._select == null) return;
@ -188,6 +227,11 @@ export class NgSelectOption implements OnDestroy {
this._select.writeValue(this._select.value);
}
/**
* @description
* Tracks simple string values bound to the option element.
* For objects, use the `ngValue` input binding.
*/
@Input('value')
set value(value: any) {
this._setElementValue(value);
@ -199,6 +243,10 @@ export class NgSelectOption implements OnDestroy {
this._renderer.setProperty(this._element.nativeElement, 'value', value);
}
/**
* @description
* Lifecycle method called before the directive's instance is destroyed. For internal use only.
*/
ngOnDestroy(): void {
if (this._select) {
this._select._optionMap.delete(this.id);

View File

@ -41,34 +41,36 @@ abstract class HTMLCollection {
}
/**
* The accessor for writing a value and listening to changes on a select element.
* @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.
*
* @see `SelectControlValueAccessor`
*
* @usageNotes
* ### Caveat: Options selection
*
* Angular uses object identity to select options. It's possible for the identities of items
* to change while the data does not. This can happen, for example, if the items are produced
* from an RPC to the server, and that RPC is re-run. Even if the data hasn't changed, the
* second response will produce objects with different identities.
* ### Using a multi-select control
*
* To customize the default option comparison algorithm, `<select multiple>` supports `compareWith`
* input. `compareWith` takes a **function** which has two arguments: `option1` and `option2`.
* If `compareWith` is given, Angular selects options by the return value of the function.
* The follow example shows you how to use a multi-select control with a reactive form.
*
* ### Syntax
* ```ts
* const countryControl = new FormControl();
* ```
*
* ```
* <select multiple [compareWith]="compareFn" [(ngModel)]="selectedCountries">
* <select multiple name="countries" [formControl]="countryControl">
* <option *ngFor="let country of countries" [ngValue]="country">
* {{country.name}}
* {{ country.name }}
* </option>
* </select>
*
* compareFn(c1: Country, c2: Country): boolean {
* return c1 && c2 ? c1.id === c2.id : c1 === c2;
* }
* ```
*
* ### Customizing option selection
*
* To customize the default option comparison algorithm, `<select>` supports `compareWith` input.
* See the `SelectControlValueAccessor` for usage.
*
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
* @publicApi
@ -80,15 +82,34 @@ abstract class HTMLCollection {
providers: [SELECT_MULTIPLE_VALUE_ACCESSOR]
})
export class SelectMultipleControlValueAccessor implements ControlValueAccessor {
/**
* @description
* The current value
*/
value: any;
/** @internal */
_optionMap: Map<string, NgSelectMultipleOption> = new Map<string, NgSelectMultipleOption>();
/** @internal */
_idCounter: number = 0;
/**
* @description
* The registered callback function called when a change event occurs on the input element.
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
*/
onTouched = () => {};
/**
* @description
* Tracks the option comparison algorithm for tracking identities when
* checking for changes.
*/
@Input()
set compareWith(fn: (o1: any, o2: any) => boolean) {
if (typeof fn !== 'function') {
@ -101,6 +122,13 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
/**
* @description
* Sets the "value" property on one or of more
* of the select's options.
*
* @param value The value
*/
writeValue(value: any): void {
this.value = value;
let optionSelectedStateSetter: (opt: NgSelectMultipleOption, o: any) => void;
@ -114,6 +142,13 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
this._optionMap.forEach(optionSelectedStateSetter);
}
/**
* @description
* Registers a function called when the control value changes
* and writes an array of the selected options.
*
* @param fn The callback function
*/
registerOnChange(fn: (value: any) => any): void {
this.onChange = (_: any) => {
const selected: Array<any> = [];
@ -140,8 +175,20 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
fn(selected);
};
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
*/
registerOnTouched(fn: () => any): void { this.onTouched = fn; }
/**
* Sets the "disabled" property on the select input element.
*
* @param isDisabled The disabled value
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}
@ -169,18 +216,14 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
}
/**
* @description
* Marks `<option>` as dynamic, so Angular can be notified when options change.
*
* @usageNotes
* ### Example
* @see `SelectMultipleControlValueAccessor`
*
* ```
* <select multiple name="city" ngModel>
* <option *ngFor="let c of cities" [value]="c"></option>
* </select>
* ```
* @ngModule FormsModule
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
* @publicApi
*/
@Directive({selector: 'option'})
export class NgSelectMultipleOption implements OnDestroy {
@ -197,6 +240,11 @@ export class NgSelectMultipleOption implements OnDestroy {
}
}
/**
* @description
* Tracks the value bound to the option element. Unlike the value binding,
* ngValue supports binding to objects.
*/
@Input('ngValue')
set ngValue(value: any) {
if (this._select == null) return;
@ -205,6 +253,11 @@ export class NgSelectMultipleOption implements OnDestroy {
this._select.writeValue(this._select.value);
}
/**
* @description
* Tracks simple string values bound to the option element.
* For objects, use the `ngValue` input binding.
*/
@Input('value')
set value(value: any) {
if (this._select) {
@ -226,6 +279,10 @@ export class NgSelectMultipleOption implements OnDestroy {
this._renderer.setProperty(this._element.nativeElement, 'selected', selected);
}
/**
* @description
* Lifecycle method called before the directive's instance is destroyed. For internal use only.
*/
ngOnDestroy(): void {
if (this._select) {
this._select._optionMap.delete(this.id);