@@ -35,6 +35,12 @@ var ngOptionsMinErr = minErr('ngOptions');
3535 * be bound to string values at present.
3636 * </div>
3737 *
38+ * <div class="alert alert-info">
39+ * **Note:** The values that are stored on the underlying option elements (i.e. `option.value`) are set
40+ * to either the indeces of the array (for array data sources) or the property names of
41+ * the object (for object data sources).
42+ * </div>
43+ *
3844 * @param {string } ngModel Assignable angular expression to data-bind to.
3945 * @param {string= } name Property name of the form under which the control is published.
4046 * @param {string= } required The control is considered valid only if value is entered.
@@ -69,7 +75,9 @@ var ngOptionsMinErr = minErr('ngOptions');
6975 * DOM element.
7076 * * `trackexpr`: Used when working with an array of objects. The result of this expression will be
7177 * used to identify the objects in the array. The `trackexpr` will most likely refer to the
72- * `value` variable (e.g. `value.propertyName`).
78+ * `value` variable (e.g. `value.propertyName`). With this the selection is preserved
79+ * even when the options are recreated (e.g. reloaded from the server).
80+ * Note that this does not work when there is a `select` expression that is different from the `trackexpr`.
7381 *
7482 * @example
7583 <example module="selectExample">
@@ -326,6 +334,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
326334
327335 var displayFn = $parse ( match [ 2 ] || match [ 1 ] ) ,
328336 valueName = match [ 4 ] || match [ 6 ] ,
337+ selectAs = / a s / . test ( match [ 0 ] ) && match [ 1 ] ,
338+ selectAsFn = selectAs ? $parse ( selectAs ) : null ,
329339 keyName = match [ 5 ] ,
330340 groupByFn = $parse ( match [ 3 ] || '' ) ,
331341 valueFn = $parse ( match [ 2 ] ? match [ 1 ] : valueName ) ,
@@ -336,7 +346,27 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
336346 // We try to reuse these if possible
337347 // - optionGroupsCache[0] is the options with no option group
338348 // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
339- optionGroupsCache = [ [ { element : selectElement , label :'' } ] ] ;
349+ optionGroupsCache = [ [ { element : selectElement , label :'' } ] ] ,
350+ idFn , isSelected ;
351+
352+ isSelected = function isSelected ( selectedSet , modelValue , locals ) {
353+ var compareValueFn ;
354+ if ( selectAsFn ) {
355+ compareValueFn = selectAsFn ;
356+ } else if ( trackFn ) {
357+ compareValueFn = trackFn ;
358+ } else {
359+ compareValueFn = valueFn ;
360+ }
361+ var compareValue = compareValueFn ( scope , locals ) ;
362+ if ( multiple ) {
363+ return isDefined (
364+ selectedSet . remove ( compareValue )
365+ ) ;
366+ } else {
367+ return modelValue === compareValue ;
368+ }
369+ } ;
340370
341371 if ( nullOption ) {
342372 // compile the element since there might be bindings in it
@@ -437,7 +467,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
437467 var selectedSet = false ;
438468 if ( multiple ) {
439469 var modelValue = ctrl . $modelValue ;
440- if ( trackFn && isArray ( modelValue ) ) {
470+ if ( trackFn && isArray ( modelValue ) && ! selectAs ) {
441471 selectedSet = new HashMap ( [ ] ) ;
442472 var locals = { } ;
443473 for ( var trackIndex = 0 ; trackIndex < modelValue . length ; trackIndex ++ ) {
@@ -501,27 +531,16 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
501531 optionGroup = optionGroups [ optionGroupName ] = [ ] ;
502532 optionGroupNames . push ( optionGroupName ) ;
503533 }
504- if ( multiple ) {
505- selected = isDefined (
506- selectedSet . remove ( trackFn ? trackFn ( scope , locals ) : valueFn ( scope , locals ) )
507- ) ;
508- } else {
509- if ( trackFn ) {
510- var modelCast = { } ;
511- modelCast [ valueName ] = modelValue ;
512- selected = trackFn ( scope , modelCast ) === trackFn ( scope , locals ) ;
513- } else {
514- selected = modelValue === valueFn ( scope , locals ) ;
515- }
516- selectedSet = selectedSet || selected ; // see if at least one item is selected
517- }
534+
535+ selected = isSelected ( selectedSet , modelValue , locals ) ;
536+ selectedSet = selectedSet || selected ;
518537 label = displayFn ( scope , locals ) ; // what will be seen by the user
519538
520539 // doing displayFn(scope, locals) || '' overwrites zero values
521540 label = isDefined ( label ) ? label : '' ;
522541 optionGroup . push ( {
523542 // either the index into array or key from object
524- id : trackFn ? trackFn ( scope , locals ) : ( keyName ? keys [ index ] : index ) ,
543+ id : ( keyName ? keys [ index ] : index ) ,
525544 label : label ,
526545 selected : selected // determine if we should be selected
527546 } ) ;
0 commit comments