Angularjs ng-options usando number for model não seleciona o valor inicial

Eu estou tentando usar ng-opções com um para ligar um valor inteiro numérico para uma lista de opções correspondentes. No meu controlador, eu tenho algo parecido com isto:

 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}}

E aqui está um jsFiddle demonstrando o problema, e algumas outras abordagens que eu tomei, mas não estou feliz com isso.

A opção de seleção está sendo inicializada com um valor vazio, em vez de “mV”, conforme esperado neste exemplo. A binding parece funcionar bem se você selecionar uma opção diferente – selectedUnitOrdinal é atualizado corretamente.

Eu notei que se você definir o valor do modelo inicial para uma string em vez de um número, então a seleção inicial funciona (veja # 3 no violino).

Eu realmente gostaria que o ng-options fosse legal com os valores das opções numéricas. Como posso conseguir isso elegantemente?

A documentação do Angular para a diretiva ng-select explica como resolver esse problema. Veja https://code.angularjs.org/1.4.7/docs/api/ng/directive/select (última seção).

Você pode criar uma diretiva de convert-to-number e aplicá-la à sua tag de seleção:

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: Eu encontrei a diretiva do doc não manipula nulos, então eu tive que ajustá-lo um pouco.

Talvez seja um pouco confuso, mas o resultado pode ser alcançado sem funções especiais nas opções ng

  

É porque quando você pega o unit.id ele está retornando uma string não um inteiro. Objetos em javascript armazenam suas chaves como strings. Então, a única maneira de fazer isso é a sua abordagem de cercar 4 por citações.

Editar

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

Você também pode definir o number filtro, este filtro analisará automaticamente o valor da string para int:

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

Apenas para adicionar a resposta de Christophe: a maneira mais fácil de achive e maintaint é fazer uma diretiva:

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 ; }); } }; }); 

A resposta de Christophe não funcionará corretamente para ‘0’, pois retorna falso em “val”. teste.

Angular está vendo sua propriedade id como uma string, adicione aspas:

 self.selectedUnitOrdinal = "4"; 

De forma muito semelhante à resposta do tymeJV, uma solução simples é converter o número de seleção padrão em uma string como esta:

 self.selectedUnitOrdinal = valueThatCameFromServer.toString(); 

Dessa forma, você não precisa codificar o número, basta converter qualquer valor recebido. É uma solução fácil, sem filtros ou diretivas.

Embora a solução fornecida por Mathew Berg funcione, ela provavelmente quebrará outros seleções que usam opções de seleção com valor de sting. Isso pode ser um problema se você tentar escrever uma diretiva universal para manipular seleções (como eu fiz).

Uma boa solução é verificar se o valor é um número (mesmo que seja uma string contendo um número) e apenas do que a conversão, da seguinte forma:

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

ou como um método de controle:

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