Search code examples
angularjsng-options

Angular: ng-options, replacing both array and model value on update


I'm working on a model which for every property update, sends itself to the server and gets recalculated. As most properties are based on lists I'm using <select>/ "dropdown" extensively.

An example on how the logic is set up:

{
  NumberList: ['123', '456', '789']
  Number: 0
}

User picks "123" from NumberList, Server responds with

{
  NumberList: ['123', '456', '789']
  Number: 123,
  OtherNumberList: ['999', '888', '777'],
  OtherNumber: 0
}

My problem is that once the user picks 123 it doesn't "stick" in the View. The select lists "flashes" (in lack of a better decription) and reverts back to 0 / Empty option. In the model however the property is correctly reflected.

Based on a old similar question here on SO I tried with ng-repeat. This almost works, but weirdly fails on some properties.

<select class="form-control" ng-model="model.Number" ng-change="mCtrl.updateModel(index)">
    <option ng-repeat="Number in model.NumberList" value="{{Number}}" ng-selected="model.Number == Number">{{Number}}</option>
</select>

My current template however fails on all properties. Thinking that it's easier to solve a general problem I've stuck with it.

<select class="form-control" ng-options="val for val in NumberList" ng-model="model.Number"></select>

For the hell of it I've tried using track by, but with no luck.

I'm really stumped on what the problem is. The only idea I have left is that since the list are arrays of strings, while the number being a number there is a type inequality. However I'm assuming ngOptions doesn't do type checking ..?

Update: As requested, the update logic. The update function gets called from the server once the model is updated. The call to the server is done from ngChange via a Service.

'update': function (index, model) {
    $window.logger('Server called update ::');
    // The array below is a list of all models
    MyService.listOfModels[index] = model;
    // Yes, this is a bit quick'n'dirty ...
    $rootScope.$apply();
}

Solution

  • You were right to question but wrong in your assumption:

    The only idea I have left is that since the list are arrays of strings, while the number being a number there is a type inequality. However I'm assuming ngOptions doesn't do type checking ..?

    ... because the ngOptions directive does use === for setting the selected value. These types need to match if you wish for the selection to be maintained after the server responds.

    Another note

    As pointed out in your question's comments and in another answer, you may also run into issues sourced from your reassigning of a new object to the model, whereas one way or another, you should probably be extending the existing object.

    You may be able to use angular.extend without much change to your code:

    'update': function (index, model) {
    ...
         angular.extend(MyService.listOfModels[index], model );
    ...
    }
    

    Demo