3

I'm experiencing an issue if I set ng-options from within a $scope.$watch statement.

The following works: <select ... ng-options="x.val as x.id for x in options"></select>

But this doesn't: <select ... ng-options="x.val as x.val for x in options"></select>

Plunker showing my issue -- click 'update options'

It seems if the model's value is set before the options are, and the label and value are equivalent, the model will not match any available option.

Is this a bug, or am I doing something wrong?

sample controller code:

$scope.myModel = 'Two';
$scope.$watch('loadTrigger', function(newValue, oldValue) {

    if (newValue == oldValue) { return; }

    $scope.options = [{id: 1, text: 'One'}, {id: 2, text: 'Two'}...];
})

sample view:

<select ng-model="myModel" ng-options="x.text as x.text for x in options">...</select>

When the watch triggers and the options get updated, the select will display a blank or default option, rather than the expected "Two". If the label and value differ (even slightly), however, everything works as expected

Galf
  • 213
  • 2
  • 5
  • Please post the relevant code in the question as well. – PSL Jan 15 '15 at 19:03
  • This is a good question, but you should add the relevant and problematic parts of your code into the question. the question should be self-sufficient – New Dev Jan 15 '15 at 19:14
  • Sorry, basically my first time posting in years -- hopefully I added enough details now. – Galf Jan 15 '15 at 19:18
  • Issue also is gone when you set `textLabel` after `dynamicOptions`. http://plnkr.co/edit/SJ3idXKS1Hyw4C14FCFb?p=preview – dfsq Jan 15 '15 at 19:31
  • Unfortunately, I don't really have flexibility to do that. When I update from one set of options to a second, the value of the model may actually not change at all. In the event that `textLabel` was already set as `Two`, assigning it after `dynamicOptions` won't have any effect – Galf Jan 15 '15 at 19:40
  • I think this is a bug. one difference i can see is ngModel priority was changed from 0 to 1 (1.2.x -> 1.3.x) and ng-options remains at a lower priority of 0. With the priority change, processing order of the directive will also get rearranged. Debugging into the core can probably tell us whats causing this issue. – PSL Jan 15 '15 at 19:54

1 Answers1

0

This is one of the murky (to me) areas of how Angular associates selected option with bound model.

In short, adding track by (and not using the select as) resolves this:

<select ng-model="textLabel" 
        ng-options="x.text for x in dynamicOptions track by x.text">
   <option value="">[No Value]</option>
</select>

EDIT: Some time ago I found this issue discussed on Angular's github, and the approach without track by works in 1.2.x Angular -> hence the murky part

New Dev
  • 48,427
  • 12
  • 87
  • 129
  • You should not mix both of them together, they are for completely different purposes. See **[here](https://code.angularjs.org/1.3.9/docs/api/ng/directive/select#-select-as-and-track-by-)** However since i cannot open plunker i am not sure what original issue may be. – PSL Jan 15 '15 at 19:25
  • 1
    Should I be concerned that this solution seems to contradict the angular docs? -- PSL beat me to it – Galf Jan 15 '15 at 19:25
  • @PSL, Ah, they finally updated the documentation - nice – New Dev Jan 15 '15 at 19:29
  • Yeah, I think I may have to go back and analyze what I'm using as a model here. Leaving out the as yields me the entire object, which isn't what I'm looking for – Galf Jan 15 '15 at 19:41