正确过滤 Angular 中的输入字段

Properly filtering an input field in Angular

我发现了这个用于过滤货币字段的指令,因此用户只需键入并隐含小数点。

它运行良好,除了用户可以在按两次字母后输入字母。我根本不希望他们能写信。

我尝试更改 type="number" 但它只允许 5 位数字,然后莫名其妙地消失了。你可以在这个 plunker 看到这个:

http://plnkr.co/edit/Y1olj7Cdz7XKqRmE7BFb?p=preview

所以要么我需要在这一行中更改某些内容(正则表达式?):

var plainNumber = viewValue.replace(/[^\d|\-+]/g, '');

或者以某种方式修复 type="number" 以保持输入超过五位数。有人知道在这里做什么吗?

我不熟悉 AngularJS,但我可以看出你的正则表达式并不完全符合你的意图。

你有这个:[^\d|\-+]

这是一个否定字符 class。所有非数字、非 +、非 - 和非 | 都将匹配。另请注意,\d 包含的内容多于 [0-9],因为它可能匹配波斯数字等。

我会使用:[^-+0-9]。通过将 - 直接放在 ^ 之后,它不需要转义。

您的解决方案的问题是您在删除字符之前等待输入字符。击键发生的速度可能比您的字段清除它们的速度快。


尽管在 Angular 或 jQuery 中没有任何经验,

我根据 here:

做了一些完美的东西

可以自由输入0-9。当输入 +- 时,它永远不会添加到末尾。相反,它出现在开头,覆盖任何现有的标志。也许你应该 运行 片段然后看看你自己:

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

app.controller('MainCtrl', function($scope) {});

app.directive('inputRestrictor', [function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, element, attr, ngModelCtrl) {
      var pattern = /[^+0-9-]/g;

      function fromUser(text) {
        if (!text)
          return text;

        var rep = /[+]/g;
        var rem = /[-]/g;
        rep.exec(text);
        rem.exec(text);
        var indexp = rep.lastIndex;
        var indexm = rem.lastIndex;
        text = text.replace(/[+-]/g, '');
        if (indexp > 0 || indexm > 0) {
          if (indexp > indexm) text = "+" + text;
          else text = "-" + text;
        }
        var transformedInput = text.replace(pattern, '');
        ngModelCtrl.$setViewValue(transformedInput);
        ngModelCtrl.$render();
        return transformedInput;
      }
      ngModelCtrl.$parsers.push(fromUser);
    }
  };
}]);
<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@1.3.0-rc.2" data-semver="1.3.0-rc.2" src="  https://code.angularjs.org/1.3.0-rc.2/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app="App">
    <div ng-controller="MainCtrl">
      <input type="text"  ng-model="inputValue" input-restrictor>
      <input type="submit" ng-click="getdata()" />
    </div>
  </body>

</html>

我从你的问题中得到的是:

  1. 只接受数字,用''替换其他所有内容
  2. 保留 2 位小数
  3. 过滤用户的输入并reflect/modify输入元素的值作为用户类型

当输入值与ng-model绑定时,实际上内部有两个主要的值:$viewValue$modelValue。他们之间的简单关系是这样的:

input DOM value -> $viewValue -> $modelValue

$parsers 仅在 $viewValue$modelValue 之间有效。所以问题是当你在 $parsers 中插入一个新的 parser 时,修改后的值只会影响 $modleValue 因为你只是在解析函数中 return 一个新值。

$parsers 是:

Array of functions to execute, as a pipeline, whenever the control reads value from the DOM. The functions are called in array order, each passing its return value through to the next. The last return value is forwarded to the $validators collection

更多信息:https://docs.angularjs.org/api/ng/type/ngModel.NgModelController#$parsers

并且解析器函数中的 returned 值不会影响 $viewValue 所以您需要做的是也更改该值并反映输入 DOM元素.

代码示例:

app.directive('format', ['$filter', function ($filter) {
    return {
        require: 'ngModel',

        link: function (scope, elem, attrs, ctrl) {
            if (!ctrl) return;

            ctrl.$parsers.unshift(function (viewValue) {
                var plainNumber = viewValue.replace(/[^\d|\-+]/g, '');
                //use angular internal 'number' filter
                plainNumber = $filter('number')(plainNumber/100,2);

                //update the $viewValue
                ctrl.$setViewValue(plainNumber);
                //reflect on the DOM element
                ctrl.$render();
                //return the modified value to next parser
                return plainNumber;
            });
        }
    };
}]);

一个有效的 plnkr 在这里:http://plnkr.co/edit/aoBWhJhlJLiEhBm5hRNX?p=preview

最后,当您输入第 6 位数字时它消失的原因是:

当您输入 6 位数字时,浏览器会将您输入的数字转换并格式化为这种格式:'1,234.56'(注意逗号',',分隔符在不同的浏览器上可能有所不同),以及您将在控制台中看到 angular 给出的警告:

The specified value "1,234.56" is not a valid number. The value must match to the following regular expression: -?(\d+|\d+.\d+|.\d+)([eE][-+]?\d+)?

这是由type='number'对输入元素的限制造成的,angular将执行额外的内部验证以匹配angular本身定义的规则。