Angularjs ng-options usando el número para el modelo no selecciona el valor inicial

Estoy tratando de usar ng-options con un para vincular un valor numérico entero a una lista de opciones correspondientes. En mi controlador, tengo algo como esto:

 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:

 
selectedUnitOrdinal: {{ctrl.selectedUnitOrdinal}}

Y aquí hay un jsFiddle que demuestra el problema, y ​​algunos otros enfoques que he tomado pero que no me satisfacen .

La opción de selección se está inicializando con un valor vacío, en lugar de “mV” como se esperaba en este ejemplo. El enlace parece funcionar bien si selecciona una opción diferente – selectedUnitOrdinal updates correctamente.

Me di cuenta de que si estableces el valor inicial del modelo en una cadena en lugar de un número, la selección inicial funciona (mira el n. ° 3 en el violín).

Realmente me gustaría que ng-options juegue bien con los valores numéricos de las opciones. ¿Cómo puedo lograr esto elegantemente?

La documentación de Angular para la directiva ng-select explica cómo resolver este problema. Ver https://code.angularjs.org/1.4.7/docs/api/ng/directive/select (última sección).

Puede crear una directiva de convert-to-number y aplicarla a su etiqueta de selección:

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 :

  

Nota: Encontré que la directiva del documento no maneja los valores nulos, así que tuve que ajustarlo un poco.

Tal vez es un poco complicado, pero el resultado se puede lograr sin funciones especiales en ng-options

  

Es porque cuando obtienes la unidad, devuelve una cadena, no un número entero. Los objetos en Javascript almacenan sus claves como cadenas. Entonces, la única forma de hacerlo es su enfoque de rodear 4 por citas.

Editar

  $scope.convertToInt = function(id){ return parseInt(id, 10); }; 

También puede definir el number filtro, este filtro automáticamente analizará el valor de la cadena a int:

  angular.module('filters').filter('number', [function() { return function(input) { return parseInt(input, 10); }; }]); 

Solo para agregar la respuesta de Christophe: la forma más fácil de lograr y mantener es hacer una directiva:

JS:

 .directive('convertToNumber', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$parsers.push(function(val) { //saves integer to model null as null return val == null ? null : parseInt(val, 10); }); ngModel.$formatters.push(function(val) { //return string for formatter and null as null return val == null ? null : '' + val ; }); } }; }); 

La respuesta de Christophe no funcionará correctamente para ‘0’ ya que devuelve falso en “val?” prueba.

Angular está viendo su propiedad de id como una cadena, agregue comillas:

 self.selectedUnitOrdinal = "4"; 

Muy similar a la respuesta de tymeJV, una solución simple es convertir el número de selección predeterminado a una cadena como esta:

 self.selectedUnitOrdinal = valueThatCameFromServer.toString(); 

De esta forma, no es necesario codificar el número, simplemente puede convertir cualquier valor recibido. Es una solución fácil sin filtros ni directivas.

Si bien la solución provista por Mathew Berg funciona, probablemente romperá otras selecciones que usan opciones de selección con valores de picadura. Esto puede ser un problema si intenta escribir una directiva universal para manejar selecciones (como lo hice).

Una buena solución es comprobar si el valor es un número (incluso si se trata de una cadena que contiene un número) y solo hacer la conversión, así:

 angular.module('').filter('intToString', [function() { return function(key) { return (!isNaN(key)) ? parseInt(key) : key; }; }]); 

o como un método de controlador:

 $scope.intToString = function(key) { return (!isNaN(key)) ? parseInt(key) : key; };