【问题标题】:Angularjs ng-options using number for model does not select initial value使用模型编号的Angularjs ng-options不选择初始值
【发布时间】:2015-03-22 18:59:15
【问题描述】:

我正在尝试使用带有 <select> 的 ng-options 将数字整数值绑定到相应选项的列表。在我的控制器中,我有这样的东西:

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 演示了这个问题,以及我已经采取但不满意的其他一些方法。

选择选项被初始化为一个空值,而不是本例中预期的“mV”。如果您选择不同的选项,绑定似乎可以正常工作 -- selectedUnitOrdinal 正确更新。

我注意到,如果您将初始模型值设置为字符串而不是数字,则初始选择有效(参见小提琴中的 #3)。

我真的希望 ng-options 能够很好地处理数字选项值。我怎样才能优雅地做到这一点?

【问题讨论】:

    标签: angularjs ng-options angularjs-ng-options


    【解决方案1】:

    您可以使用 ng-value 属性。像这样:

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

    【讨论】:

    • 这是最简单/最简单的解决方案
    【解决方案2】:

    将unitsOptions中的id属性设为数字

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

    http://jsfiddle.net/htwc10nx/

    【讨论】:

      【解决方案3】:

      我认为其他解决方案对于简单地将值建立为整数来说过于复杂。我会使用:

      <select ng-model="model.id">
          <option ng-value="{{ 0 }}">Zero</option>
          <option ng-value="{{ 1 }}">One</option>
          <option ng-value="{{ 2 }}">Two</option>
      </select>
      

      【讨论】:

        【解决方案4】:
        <select ng-model="ctrl.selectedUnitOrdinal" ng-options="+(unit.id) as unit.text for unit in ctrl.unitsOptions"></select>
        

        【讨论】:

        • 虽然此代码 sn-p 可能是解决方案,但包含解释确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因
        • 这是修复我的错误的原因 - 谢谢。我建议 + 将此值转换为字符串。
        【解决方案5】:

        Angular 的ng-select 指令文档解释了如何解决这个问题。见https://code.angularjs.org/1.4.7/docs/api/ng/directive/select(最后一节)。

        您可以创建一个convert-to-number 指令并将其应用于您的选择标签:

        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>
        

        注意:我发现文档中的指令不处理空值,所以我不得不稍微调整一下。

        【讨论】:

        • 大部分时间都是convert-to-string,只需将parseInt改为String
        • 这应该是公认的答案,因为它更通用并且不依赖于ng-options。另外,请记住,这不适用于任何数字,而仅适用于整数。如果你想让浮点数起作用,请使用parseFloat(),但如果你在比较浮点数是否相等,你可能做错了。
        • 不错的解决方案。但是当您的选择选项中有 0 时,由于实现,它会给出 null 。处理这种情况需要稍作调整。
        • 不错!我正在寻找一种将表单中的字符串值转换为强类型对象(带有日期、数字、布尔值等)的方法。这种方法看起来不错!
        • 太棒了,但是当值为 0 时这对我不起作用,因为 0 == false。将其重写为: return (val||0===val) ? parseInt(val, 10) : null;并返回 (val||0===val) ? '' + val : null;
        【解决方案6】:

        与 tymeJV 的回答非常相似,简单的解决方法是将默认选择编号转换为这样的字符串:

        self.selectedUnitOrdinal = valueThatCameFromServer.toString();
        

        这样,您不必对数字进行硬编码,只需转换任何接收到的值。无需任何过滤器或指令即可轻松解决。

        【讨论】:

          【解决方案7】:

          可能有点乱,但是在ng-options中不需要特殊功能也可以实现结果

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

          【讨论】:

          • 这真的是最简单的答案。 jsFiddle 中使用的 angularJS 库版本 1.3.10 有一个错误,+unit.id 表示法不起作用,但它从 1.4.0 开始起作用;见working jsFiddle
          • 但是option的值是:value="number:0",with 'number'
          • 凌乱?这太棒了!比注入自定义指令更清洁、更简单。谢谢!
          • 这真的是去这里的正确方式,对我帮助很大。你能解释一下ng-options中“+”的意义吗?
          • @istrupin 这只是类型转换。更多关于 MDN:Unary plus operator
          【解决方案8】:

          只是添加克里斯托夫的回答:实现和维护它的最简单方法是制定指令:

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

          Christophe 的回答对于“0”不能正常工作,因为它在“val?”上返回 false。测试。

          【讨论】:

            【解决方案9】:

            虽然 Mathew Berg 提供的解决方案有效,但它可能会破坏其他使用 sting-valued 选择选项的选择。如果您尝试编写一个通用指令来处理选择(就像我所做的那样),这可能是一个问题。

            一个很好的解决方法是检查该值是否是一个数字(即使它是一个包含数字的字符串)并且只进行转换,如下所示:

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

            【讨论】:

              【解决方案10】:

              你也可以定义过滤器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);
                      };
                  }]);
              

              【讨论】:

              • 在使用parseInt 时,应始终使用基数,例如:return parseInt(input, 10);
              【解决方案11】:

              这是因为当您获取 unit.id 时,它返回的是字符串而不是整数。 javascript 中的对象将它们的键存储为字符串。所以唯一的办法就是用引号包围 4。

              编辑

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

              【讨论】:

              • 谢谢。我从服务器得到一个数值,我需要发回一个数值。这种情况很多。我真的想避免在控制器中编写转换代码。 (似乎我在淘汰赛中从未遇到过这种障碍)。我可以得到我想要的东西的聪明/懒惰的方式是什么?
              • Angular 在这方面比淘汰赛更具限制性,我猜 :)。无论如何,我已经编辑了这个问题,向你展示了一个你可以做的选择。
              • 好吧,我几乎可以忍受。
              • 啊哈!我已经对此进行了更多的研究,并且感谢您的回答和同事的一些见解,我可以通过在构建选项数组时执行{ id: parseInt(key), text: self.unitOptionsFromServer[key] } 来获得我想要的东西,然后使用 ng-options 一切都按预期工作。让我感到困惑的部分是,即使您可以将对象键表示为数值,JS 将它们更改为字符串。
              • 完全是我的错,应该注意到你正在转换它,我只是快速查看了 dom。恭喜你弄明白了!旁注我会放 parseInt(key, 10);
              【解决方案12】:

              Angular 将您的 id 属性视为字符串,添加引号:

              self.selectedUnitOrdinal = "4";
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2017-12-31
                • 1970-01-01
                • 2018-06-21
                • 1970-01-01
                • 2012-10-14
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多