Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs ng-options using number for model does not select initial value

I'm trying to use ng-options with a <select> to bind a numeric integer value to a list of corresponding options. In my controller, I have something like this:

myApp.controller('MyCtrl', function() {
    var self = this;

    var unitOptionsFromServer = {
        2: "mA",
        3: "A",
        4: "mV",
        5: "V",
        6: "W",
        7: "kW"
    };

    self.unitsOptions = Object.keys(unitOptionsFromServer).map(function (key) {
        return { id: key, text: unitOptionsFromServer[key] };
    });

    self.selectedUnitOrdinal = 4; // Assume this value came from the server.
});

HTML:

<div ng-controller="MyCtrl as ctrl">
    <div>selectedUnitOrdinal: {{ctrl.selectedUnitOrdinal}}</div>
    <select ng-model="ctrl.selectedUnitOrdinal" ng-options="unit.id as unit.text for unit in ctrl.unitsOptions"></select>
</div>

And here's a jsFiddle demonstrating the problem, and some other approaches I've taken but am not happy with.

The select option is being initialized with an empty value, instead of "mV" as expected in this example. The binding seems to work fine if you select a different option -- selectedUnitOrdinal updates properly.

I've noticed that if you set the initial model value to a string instead of a number, then the initial selection works (see #3 in the fiddle).

I really would like ng-options to play nice with numeric option values. How can I achieve this elegantly?

like image 704
BrandonLWhite Avatar asked Jan 23 '15 17:01

BrandonLWhite


People also ask

How do I set default selected value in ng-options?

In my opinion the correct way to set a default value is to simply pre-fill your ng-model property with the value selected from your ng-options , angular does the rest. Essentially when you define the $scope property your select will bind to assign it the default value from your data array.

What is NG-model options in AngularJS?

The ng-model-options directive is used to control the binding of an HTML form element and a variable in the scope. You can specify that the binding should wait for a specific event to occur, or wait a specific number of milliseconds, and more, see the legal values listed in the parameter values below.

How do you use NG-options?

The ng-options directive fills a <select> element with <options>. The ng-options directive uses an array to fill the dropdown list. In many cases it would be easier to use the ng-repeat directive, but you have more flexibility when using the ng-options directive.

What is the difference between ng-model and data NG model?

There is no difference between ng-model and data-ng-model if you see in terms of AngularJs. Actually, 'data' used as prefix to validate HTML5 validation. So, it is good practice to use data-ng-model , however, you can use ng-model as well. There is no problem in that also.


4 Answers

Angular's documentation for the ng-select directive explains how to solve this problem. See https://code.angularjs.org/1.4.7/docs/api/ng/directive/select (last section).

You can create a convert-to-number directive and apply it to your select tag:

JS:

module.directive('convertToNumber', function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
      ngModel.$parsers.push(function(val) {
        return val != null ? parseInt(val, 10) : null;
      });
      ngModel.$formatters.push(function(val) {
        return val != null ? '' + val : null;
      });
    }
  };
});

HTML:

<select ng-model="model.id" convert-to-number>
  <option value="0">Zero</option>
  <option value="1">One</option>
  <option value="2">Two</option>
</select>

Note: I found the directive from the doc does not handle nulls so I had to tweak it a little.

like image 188
Christophe L Avatar answered Oct 14 '22 07:10

Christophe L


Maybe it's a bit messy, but result can be achieved without special functions right in ng-options

<select ng-model="ctrl.selectedUnitOrdinal" ng-options="+(unit.id) as unit.text for unit in ctrl.unitsOptions"></select>
like image 44
re-gor Avatar answered Oct 14 '22 06:10

re-gor


It's because when you get the unit.id it's returning a string not an integer. Objects in javascript store their keys as strings. So the only way to do it is your approach of surrounding 4 by quotations.

Edit

<select ng-model="ctrl.selectedUnitOrdinal" ng-options="convertToInt(unit.id) as unit.text for unit in ctrl.unitsOptions"></select>

$scope.convertToInt = function(id){
    return parseInt(id, 10);
};
like image 17
Mathew Berg Avatar answered Oct 14 '22 06:10

Mathew Berg


You can also define filter number, this filter will automatically parse string value to int:

<select ng-model="ctrl.selectedUnitOrdinal" ng-options="unit.id|number as unit.text for unit in ctrl.unitsOptions"></select>


angular.module('filters').filter('number', [function() {
        return function(input) {
            return parseInt(input, 10);
        };
    }]);
like image 9
zooblin Avatar answered Oct 14 '22 07:10

zooblin