Подтвердить что ты не робот

Параметры 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 играли хорошо с числовыми значениями опций. Как я могу достичь этого элегантно?

4b9b3361

Ответ 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] };
    });