11import {
2- Query ,
32 Directive ,
43 Renderer ,
5- Self ,
64 forwardRef ,
75 Provider ,
86 ElementRef ,
9- QueryList
7+ Input ,
8+ Host ,
9+ OnDestroy ,
10+ Optional
1011} from 'angular2/core' ;
11-
12- import { ObservableWrapper } from 'angular2/src/facade/async' ;
1312import { NG_VALUE_ACCESSOR , ControlValueAccessor } from './control_value_accessor' ;
14- import { CONST_EXPR } from 'angular2/src/facade/lang' ;
13+ import {
14+ CONST_EXPR ,
15+ StringWrapper ,
16+ isPrimitive ,
17+ isPresent ,
18+ looseIdentical
19+ } from 'angular2/src/facade/lang' ;
20+
21+ import { MapWrapper } from 'angular2/src/facade/collection' ;
1522
1623const SELECT_VALUE_ACCESSOR = CONST_EXPR ( new Provider (
1724 NG_VALUE_ACCESSOR , { useExisting : forwardRef ( ( ) => SelectControlValueAccessor ) , multi : true } ) ) ;
1825
19- /**
20- * Marks `<option>` as dynamic, so Angular can be notified when options change.
21- *
22- * ### Example
23- *
24- * ```
25- * <select ngControl="city">
26- * <option *ngFor="#c of cities" [value]="c"></option>
27- * </select>
28- * ```
29- */
30- @Directive ( { selector : 'option' } )
31- export class NgSelectOption {
26+ function _buildValueString ( id : string , value : any ) : string {
27+ if ( ! isPrimitive ( value ) ) value = "Object" ;
28+ return StringWrapper . slice ( `${ id } : ${ value } ` , 0 , 50 ) ;
29+ }
30+
31+ function _extractId ( valueString : string ) : string {
32+ return valueString . split ( ":" ) [ 0 ] ;
3233}
3334
3435/**
@@ -37,27 +38,77 @@ export class NgSelectOption {
3738@Directive ( {
3839 selector : 'select[ngControl],select[ngFormControl],select[ngModel]' ,
3940 host : { '(input)' : 'onChange($event.target.value)' , '(blur)' : 'onTouched()' } ,
40- bindings : [ SELECT_VALUE_ACCESSOR ]
41+ providers : [ SELECT_VALUE_ACCESSOR ]
4142} )
4243export class SelectControlValueAccessor implements ControlValueAccessor {
43- value : string ;
44+ value : any ;
45+ _optionMap : Map < string , any > = new Map < string , any > ( ) ;
46+ _idCounter : number = 0 ;
47+
4448 onChange = ( _ : any ) => { } ;
4549 onTouched = ( ) => { } ;
4650
47- constructor ( private _renderer : Renderer , private _elementRef : ElementRef ,
48- @Query ( NgSelectOption , { descendants : true } ) query : QueryList < NgSelectOption > ) {
49- this . _updateValueWhenListOfOptionsChanges ( query ) ;
50- }
51+ constructor ( private _renderer : Renderer , private _elementRef : ElementRef ) { }
5152
5253 writeValue ( value : any ) : void {
5354 this . value = value ;
54- this . _renderer . setElementProperty ( this . _elementRef . nativeElement , 'value' , value ) ;
55+ var valueString = _buildValueString ( this . _getOptionId ( value ) , value ) ;
56+ this . _renderer . setElementProperty ( this . _elementRef . nativeElement , 'value' , valueString ) ;
5557 }
5658
57- registerOnChange ( fn : ( ) => any ) : void { this . onChange = fn ; }
59+ registerOnChange ( fn : ( value : any ) => any ) : void {
60+ this . onChange = ( valueString : string ) => { fn ( this . _getOptionValue ( valueString ) ) ; } ;
61+ }
5862 registerOnTouched ( fn : ( ) => any ) : void { this . onTouched = fn ; }
5963
60- private _updateValueWhenListOfOptionsChanges ( query : QueryList < NgSelectOption > ) {
61- ObservableWrapper . subscribe ( query . changes , ( _ ) => this . writeValue ( this . value ) ) ;
64+ _registerOption ( ) : string { return ( this . _idCounter ++ ) . toString ( ) ; }
65+
66+ _getOptionId ( value : any ) : string {
67+ for ( let id of MapWrapper . keys ( this . _optionMap ) ) {
68+ if ( looseIdentical ( this . _optionMap . get ( id ) , value ) ) return id ;
69+ }
70+ return null ;
71+ }
72+
73+ _getOptionValue ( valueString : string ) : any { return this . _optionMap . get ( _extractId ( valueString ) ) ; }
74+ }
75+
76+ /**
77+ * Marks `<option>` as dynamic, so Angular can be notified when options change.
78+ *
79+ * ### Example
80+ *
81+ * ```
82+ * <select ngControl="city">
83+ * <option *ngFor="#c of cities" [value]="c"></option>
84+ * </select>
85+ * ```
86+ */
87+ @Directive ( { selector : 'option' } )
88+ export class NgSelectOption implements OnDestroy {
89+ id : string ;
90+
91+ constructor ( private _element : ElementRef , private _renderer : Renderer ,
92+ @Optional ( ) @Host ( ) private _select : SelectControlValueAccessor ) {
93+ if ( isPresent ( this . _select ) ) this . id = this . _select . _registerOption ( ) ;
94+ }
95+
96+ @Input ( )
97+ set value ( value : any ) {
98+ if ( this . _select == null ) return ;
99+ this . _select . _optionMap . set ( this . id , value ) ;
100+ this . _setElementValue ( _buildValueString ( this . id , value ) ) ;
101+ this . _select . writeValue ( this . _select . value ) ;
102+ }
103+
104+ _setElementValue ( value : string ) : void {
105+ this . _renderer . setElementProperty ( this . _element . nativeElement , 'value' , value ) ;
106+ }
107+
108+ ngOnDestroy ( ) {
109+ if ( isPresent ( this . _select ) ) {
110+ this . _select . _optionMap . delete ( this . id ) ;
111+ this . _select . writeValue ( this . _select . value ) ;
112+ }
62113 }
63114}
0 commit comments