【问题标题】:Is it possible to transform a value between view and model in AngularJS for input?是否可以在 AngularJS 中转换视图和模型之间的值以供输入?
【发布时间】:2012-11-16 16:36:54
【问题描述】:

AngularJS 新手。试图弄清楚我将如何做到这一点,或者是否有可能。

我知道我可以使用

将值绑定到输入框
<input type="number" ng-model="myvalue">

但是如果我想要模型和视图之间的值被转换怎么办?

例如,对于货币,我喜欢以美分存储我的价值。但是,我想允许我的用户输入美元金额。所以我需要在视图和控制器之间将值转换为 100 倍,即在模型中我有 100,在视图中我有 1。

这可能吗?如果是这样,我该如何实现?

【问题讨论】:

标签: angularjs


【解决方案1】:

我遇到了和你一样的问题。我开始使用 wciu 的解决方案,但遇到了值会在美分和美元之间闪烁的问题。我最终连接到了用于在视图和模型之间进行绑定的管道。

merchantApp.directive('transformTest', function() {
  return { restrict: 'A',
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {

      if(ngModel) { // Don't do anything unless we have a model

        ngModel.$parsers.push(function (value) {
          return value*100;
        });

        ngModel.$formatters.push(function (value) {
          return value/100;
        });

      }
    }
  };
});

【讨论】:

  • 您能否举例说明如何在视图中使用此解决方案?
  • 谢谢!迄今为止最好的解决方案。 @theDmi 您需要在输入字段中包含此指令。
  • 谢谢 - 我也在做美元对美分(内部美分,用户使用美元)并使用它,称之为“dollarsToCents”。 (我还在内部添加了一些 .toFixed() 调用,因为我遇到了舍入错误)。至于在 HTML 中使用它,这行得通:&lt;input ng-model="item.unit_price_cents" dollars-to-cents="true"&gt;
  • 对我来说,将格式化程序作为数字推送与 ng-maxlength 冲突。这修复了它:(value / 100).toString()
  • 我期待一个使用像&lt;input type="number" ng-model="myvalue | converter"&gt; 这样的管道的解决方案。不能这样做吗?
【解决方案2】:

我只会使用 Object.defineProperty 来解决这个问题,例如:

var prop = 0;
Object.defineProperty($scope, "prop", {
    get: function () {
        return prop / 100;
    },
    set: function (value) {
        prop = parseInt(value) * 100;
    }
});

变量 prop 现在总是 = $scope.prop * 100。

【讨论】:

    【解决方案3】:

    您可以在输入元素上使用ngChange 可选方法来执行一个函数,将用户输入操作为您在每次更改时寻找的格式。

        function Ctrl($scope) {
            $scope.valueEntered = '';
            $scope.value = '';
    
            $scope.valueEnteredChanged = function () {
                // more robust logic here
                $scope.value = $scope.valueEntered * 100;
            }
        }
    

    并带有如下所示的标记。

    <div ng-controller="Ctrl">
        <input type="number" ng-model="valueEntered" ng-change="valueEnteredChanged()" /><br />
        <span ng-bind="valueEntered"></span><br />
        <span ng-bind="value"></span>
    </div>
    

    【讨论】:

    • 这是我能想到的最好的方法,不用写更复杂的指令,而且这种方法肯定更简单!
    • 谢谢,在我看到这个之前我实际上写了一些类似的东西,但是没有两个 span 元素。这些有必要吗?
    • 不,它们不是必需的。我刚刚添加它们是为了让您能够查看存储在各个范围项中的值。
    【解决方案4】:

    从这个页面 http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController 了解如何使用 NgModelController 的指令来执行此操作

    基本上,以下指令将对带有 transformTest 作为属性的输入字段乘以/除以 100。

    merchantApp.directive('transformTest', function() {
      return { restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attrs, ngModel) {
          if (!ngModel) return;
    
          ngModel.$render = function () {
            element.val(ngModel.$viewValue / 100);
          }
    
          element.bind('blur keyup change', function() {
            scope.$apply(read);
            ngModel.$render();
          }); 
    
          read();
    
          function read() {
            ngModel.$setViewValue(element.val() * 100);
          }
        }
      };
    });
    

    【讨论】:

      【解决方案5】:

      $观察模型/美元价值并保持美分财产同步:

      function MyCtrl($scope) {
          $scope.$watch('dollars', function(dollars) {
              $scope.cents = $scope.dollars * 100;
          })
      }​
      

      标记:

      <input type="number" ng-model="dollars">
      <br>{{dollars}} {{cents}}
      

      【讨论】:

      • 如果使用这种方法,我可能会在另一个方向包含另一个 $watch(即使我目前没有任何其他代码修改 cents 变量)以避免将来的代码带来centsdollars 变量不同步 - 这里显示的实现允许。
      • 请注意,这种方法也会降低性能,因为input-元素将更新作用域上的dollars 变量,它会导致一个摘要循环来更新cents 变量。这反过来又会导致另一个摘要循环。在@gingermusketeer 的回答中使用$parsers$formatters 方法可以防止这个额外的循环,因为值在写入作用域之前已被转换。
      猜你喜欢
      • 1970-01-01
      • 2018-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-17
      • 1970-01-01
      • 1970-01-01
      • 2020-03-15
      相关资源
      最近更新 更多