Параметры Angularjs ng с использованием номера для модели не выбирают начальное значение
Я пытаюсь использовать ng-options с <select>
, чтобы связать числовое целочисленное значение со списком соответствующих параметров. В моем контроллере у меня есть что-то вроде этого:
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>
И вот jsFiddle, демонстрирующий проблему, и некоторые другие подходы, которые я предпринял, но меня не устраивает.
Параметр select инициализируется пустым значением, а не "mV", как ожидалось в этом примере. Связывание, кажется, работает нормально, если вы выберете другой вариант - selectedUnitOrdinal обновляется должным образом.
Я заметил, что если вы установите начальное значение модели на строку вместо числа, тогда начальный отбор будет работать (см. # 3 в скрипте).
Мне действительно хотелось бы, чтобы ng-options играли хорошо с числовыми значениями опций. Как я могу достичь этого элегантно?
Ответы
Ответ 1
Angular документация для директивы ng-select
объясняет, как решить эту проблему. См. https://code.angularjs.org/1.4.7/docs/api/ng/directive/select (последний раздел).
Вы можете создать директиву convert-to-number
и применить ее к вашему тегу select:
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>
Примечание. Я обнаружил, что директива из документа не обрабатывает значения null, поэтому мне пришлось немного ее подстроить.
Ответ 2
Возможно, это немного беспорядочно, но результат может быть достигнут без специальных функций прямо в ng-options
<select ng-model="ctrl.selectedUnitOrdinal" ng-options="+(unit.id) as unit.text for unit in ctrl.unitsOptions"></select>
Ответ 3
Это потому, что когда вы получаете unit.id, он возвращает строку, а не целое число. Объекты в javascript хранят свои ключи как строки. Таким образом, единственный способ сделать это - ваш подход окружающих 4 по котировкам.
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);
};
Ответ 4
Вы также можете определить фильтр number
, этот фильтр автоматически проанализирует строковое значение 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);
};
}]);
Ответ 5
Просто добавьте отзыв Кристофа: самый простой способ добиться и поддерживать его - сделать директиву:
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 ;
});
}
};
});
Ответ Кристофа не будет корректно работать для "0", поскольку он возвращает false на "val?". тест.
Ответ 6
Angular видит ваше свойство id
как строку, добавляет кавычки:
self.selectedUnitOrdinal = "4";
Ответ 7
Очень похоже на ответ tymeJV, простым обходным путем является преобразование номера выбора по умолчанию в строку следующим образом:
self.selectedUnitOrdinal = valueThatCameFromServer.toString();
Таким образом, вам не нужно жестко указывать номер, вы можете просто преобразовать любое полученное значение. Это легкое исправление без каких-либо фильтров или директив.
Ответ 8
Я думаю, что другие решения слишком сложны для простого установления значения как целого числа. Я хотел бы использовать:
<select ng-model="model.id">
<option ng-value="{{ 0 }}">Zero</option>
<option ng-value="{{ 1 }}">One</option>
<option ng-value="{{ 2 }}">Two</option>
</select>
Ответ 9
<select ng-model="ctrl.selectedUnitOrdinal" ng-options="+(unit.id) as unit.text for unit in ctrl.unitsOptions"></select>
Ответ 10
В то время как решение, предоставленное Мэтью Бергом, работает, оно, вероятно, сломает другие выборки, которые используют варианты выбора с учетом жала. Это может быть проблемой, если вы попытаетесь написать одну универсальную директиву для обработки выборок (как и я).
Хорошим обходным решением является проверка того, является ли значение числом (даже если это строка, содержащая число), и только, чем преобразование, например:
angular.module('<module name>').filter('intToString', [function() {
return function(key) {
return (!isNaN(key)) ? parseInt(key) : key;
};
}]);
или как метод контроллера:
$scope.intToString = function(key) {
return (!isNaN(key)) ? parseInt(key) : key;
};
Ответ 11
Сделать свойство id в unitOptions как число
self.unitsOptions = Object.keys(unitOptionsFromServer).map(function (key) {
return { id: +key, text: unitOptionsFromServer[key] };
});