diff --git a/modules/angular2/src/common/forms/directives/select_control_value_accessor.ts b/modules/angular2/src/common/forms/directives/select_control_value_accessor.ts index cc91122e1f..e10346cc0b 100644 --- a/modules/angular2/src/common/forms/directives/select_control_value_accessor.ts +++ b/modules/angular2/src/common/forms/directives/select_control_value_accessor.ts @@ -1,21 +1,78 @@ import { - Query, Directive, Renderer, - Self, forwardRef, Provider, ElementRef, - QueryList + Input, + Host, + OnDestroy, + Optional } from 'angular2/core'; - -import {ObservableWrapper} from 'angular2/src/facade/async'; import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor'; -import {CONST_EXPR} from 'angular2/src/facade/lang'; +import { + CONST_EXPR, + StringWrapper, + isPrimitive, + isPresent, + looseIdentical +} from 'angular2/src/facade/lang'; + +import {MapWrapper} from 'angular2/src/facade/collection'; const SELECT_VALUE_ACCESSOR = CONST_EXPR(new Provider( NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => SelectControlValueAccessor), multi: true})); +function _buildValueString(id: string, value: any): string { + if (!isPrimitive(value)) value = "Object"; + return StringWrapper.slice(`${id}: ${value}`, 0, 50); +} + +function _extractId(valueString: string): string { + return valueString.split(":")[0]; +} + +/** + * The accessor for writing a value and listening to changes on a select element. + */ +@Directive({ + selector: 'select[ngControl],select[ngFormControl],select[ngModel]', + host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'}, + providers: [SELECT_VALUE_ACCESSOR] +}) +export class SelectControlValueAccessor implements ControlValueAccessor { + value: any; + _optionMap: Map = new Map(); + _idCounter: number = 0; + + onChange = (_: any) => {}; + onTouched = () => {}; + + constructor(private _renderer: Renderer, private _elementRef: ElementRef) {} + + writeValue(value: any): void { + this.value = value; + var valueString = _buildValueString(this._getOptionId(value), value); + this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', valueString); + } + + registerOnChange(fn: (value: any) => any): void { + this.onChange = (valueString: string) => { fn(this._getOptionValue(valueString)); }; + } + registerOnTouched(fn: () => any): void { this.onTouched = fn; } + + _registerOption(): string { return (this._idCounter++).toString(); } + + _getOptionId(value: any): string { + for (let id of MapWrapper.keys(this._optionMap)) { + if (looseIdentical(this._optionMap.get(id), value)) return id; + } + return null; + } + + _getOptionValue(valueString: string): any { return this._optionMap.get(_extractId(valueString)); } +} + /** * Marks `