【问题标题】:Angular model.$viewValue not showing in input fieldAngular model.$viewValue 未显示在输入字段中
【发布时间】:2017-07-21 02:50:49
【问题描述】:

我之前写过这个[问题][1],现在我遇到的问题是model.$viewValue与我在输入框中看到的值不一样。

<div amount-input-currency="" ng-model="data.amount" ></div>

这是我的指令(isNumeric 和类似的并不重要):

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.data = { amount: ''};
});
app.directive('amountInputCurrency', function () {            
  return {
    restrict: 'EA',
    require: 'ngModel',
    templateUrl: 'inputCurrency.tmpl.html',
    scope: {
      model: '=ngModel',
    },
    link: function (scope, elem, attrs, ngModelCtrl) {
      scope.model2 = ngModelCtrl;
      console.log("I am in the directive!");
      var myAmountCurrencyType = elem.find('.cb-amount-input-currency');

      scope.onFocus = function() {
          removeThousandSeparator();
      };

      scope.onBlur = function() {
          renderValue();
          ngModelCtrl.$render();
      };


      //format text going to user (model to view)
      ngModelCtrl.$formatters.push(function(value) {
        return parseValue(value);
      });

      //format text from the user (view to model)
      ngModelCtrl.$parsers.push(function(value) {
        var num = Number(value);
        if(isNumeric(num)) {
            var decimal = 2;
            return formatAmount();
        } else {
            return value;
        }
      });

      function isNumeric(val) {
        return Number(parseFloat(val))==val;
      }

    }
  }
});

这是我的模板:

scope.model: {{model}}<br>
viewValue: {{model2.$viewValue}}<br>
modelValue: {{model2.$modelValue}}<br>
<input type="text" class="amount-input-currency form-control" x-ng-model="model" ng-focus="onFocus()" ng-blur="onBlur()"></input>

【问题讨论】:

    标签: angularjs input formatting angular-ngmodel angular-template


    【解决方案1】:

    使用ngModelCtrl.$setViewValue() 设置 viewValue 以更新模型,而不是直接设置 $viewValue 字段。但我完全不确定在这种情况下使用 NgModelController 有什么意义。

    如果唯一的目的是格式化文本框的值,操作输入元素值而不是 NgModelController 字段。

    function renderValue() {
        var myAmountCurrencyType = elem.find('input');
        var value = myAmountCurrencyType.val();
    
        var decimal = 2;
        if (value != undefined && value !="") {
          myAmountCurrencyType.val(formatAmount());
        }
      }
    

    这样它不会更新模型。如果您想完全控制数据绑定,可以考虑从输入元素 x-ng-model="model" 中删除绑定,并在指令中使用 NgModelController 实现它。

    【讨论】:

    • 嗨,谢谢...重点是当我不在输入字段(例如 1.000.000,00)上时格式正确的货币值,并在我获得焦点时删除千分...在第 62 行和第 86 行中使用 $setViewValue() onBlur 事件更改值在范围、viewValue 和 modelValue 中是相同的(我希望在 viewValue 中有一个格式正确的值,但不在范围和模型中)。跨度>
    • 好的。现在我明白了。我相应地改变了我的答案
    【解决方案2】:

    Checkout Formatters and Parser,它是如何做你想做的,但你必须要求 ngModel 来 hook append formatter 或 parser。

    一篇关于他们的好文章:https://alexperry.io/angularjs/2014/12/10/parsers-and-formatters-angular.html

    问候。

    【讨论】:

      【解决方案3】:

      如果你可以在没有格式化程序和解析器的情况下做你需要做的事情,那就更好了,因为你以角度方式工作更多,如果你可以避免在指令中使用 ng-model,如果你可以在没有它的情况下进行管理,因为这会导致很多也很乱。

      至于您的问题,我将展示一个不需要格式化程序和解析器的解决方案,如果您必须使用格式化程序和解析器,我希望这是您想要的,但它基本上与以下内容相同解决方案:

      index.html:

      <!DOCTYPE html>
      <html ng-app="plunker">
      
        <head>
          <meta charset="utf-8" />
          <title>AngularJS Plunker</title>
          <script>document.write('<base href="' + document.location + '" />');</script>
          <link rel="stylesheet" href="style.css" />
          <script data-require="angular.js@1.2.x" src="http://code.angularjs.org/1.2.15/angular.js" data-semver="1.2.15"></script>
          <script src="app.js"></script>
        </head>
      
        <body ng-controller="MainCtrl">
          <!--<div amount-input-currency="" ng-model="data.amount" ></div>-->
          <amount-input-currency model="data.amount"></amount-input-currency>
        </body>
      
      </html> 
      

      amountInputCurrency.tmpl.html:

      scope.model: {{model}}<br>
      viewValue: {{model2.$viewValue}}<br>
      modelValue: {{model2.$modelValue}}<br>
      <input type="text" class="cb-amount-input-currency form-control" ng-model="model" ng-focus="onFocus()" ng-blur="onBlur()">
      

      app.js:

      var app = angular.module('plunker', []);
      
      app.controller('MainCtrl', function($scope) {
        $scope.data = { amount: ''};
      });
      app.directive('amountInputCurrency', function () {
        var isAllowedKey = function (k, v) {
            return (
                k === 8 || k === 9 || k === 46 ||
                (k > 47 && k < 58) ||
                (k > 95 && k < 106) ||
                (k > 36 && k < 41) ||
                (k === 188 && (!v || v.search(/(\.|\,)/)<0)) ||
                ((k === 190 || k === 110) && (!v || v.search(/(\.|\,)/)<0))
            );
        };
      
        return {
          restrict: 'E',
          // require: 'ngModel',
          templateUrl: 'amountInputCurrency.tmpl.html',
          scope: {
            model: '=',
          },
          link: function (scope, elem, attrs) {
            // scope.model2 = ngModelCtrl;
            console.log("I am in the directive!");
            var myAmountCurrencyType = elem.find('.cb-amount-input-currency');
              myAmountCurrencyType.on('keydown', function (e) {
                //if (!isAllowedKey(e.which, scope.model)) {
                if (!isAllowedKey(e.which, scope.model)) {
                    e.preventDefault();
                }
            });
      
            scope.onFocus = function() {
                removeThousandSeparator();
            };
      
            scope.onBlur = function() {
                renderValue();
                // ngModelCtrl.$render();
                // scope.model = ngModelCtrl.$viewValue;
            };
      
      
            // //format text going to user (model to view)
            // ngModelCtrl.$formatters.push(function(value) {
            //   return parseValue(value);
            // });
      
            // //format text from the user (view to model)
            // ngModelCtrl.$parsers.push(function(value) {
            //   var num = Number(value);
            //   if(isNumeric(num)) {
            //       var decimal = 2;
            //       return formatAmount(Number(num).toFixed(decimal), decimal, ',', '.');
            //   } else {
            //       return value;
            //   }
            // });
      
            function isNumeric(val) {
              return Number(parseFloat(val))==val;
            }
      
            function renderValue() {
              var value = String(scope.model || '');
              var decimal = attrs.cbAmountDecimal || 2;
              if (value != undefined && value !="") {
                scope.model = formatAmount(value, decimal, ',', '.');
                // ngModelCtrl.$render();
              }
            }
      
            function formatAmount(amount, c, d, t) {
              if (amount.indexOf(',') !== -1) {
                  if (amount.indexOf('.') !== -1) {
                      amount = amount.replace(/\./g,'');  //remove thousand separator
                  }
                  amount = amount.replace(/\,/g,'.');
              }
              c = isNaN(c = Math.abs(c)) ? 2 : c;
              d = d === undefined ? "." : d;
              t = t === undefined ? "," : t;
              var n = amount,
                  s = n < 0 ? "-" : "",
                  i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
                  j = (j = i.length) > 3 ? j % 3 : 0;
              return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
            }
      
            function removeThousandSeparator() {
              if(scope.model != undefined && scope.model !="") {
                  scope.model = scope.model.replace(/\./g,'');
                  // ngModelCtrl.$render();
                  // scope.model = ngModelCtrl.$viewValue;
              }
            }
      
            function parseValue(viewValue) {
              var num = 0;
              if(isNumeric(viewValue)) {
                  num = viewValue;
              } else {
                  num = viewValue ? viewValue.replace(/,/g,'.') : viewValue;
              }
              return num;
            }
      
          }
        }
      });
      

      如果这不是您想要的,那么我真的很抱歉,请评论我的解决方案中存在的问题,我会尽力帮助您。

      【讨论】:

      • 如果他想对其指令进行一些表单验证怎么办?继续使用 ngModel,您只需挂钩 Angular NgModelController 的生命周期,它使您的指令/组件与 Angular 表单系统兼容。
      猜你喜欢
      • 1970-01-01
      • 2015-05-11
      • 1970-01-01
      • 1970-01-01
      • 2017-02-28
      • 2021-03-23
      • 2014-06-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多