在AngularJS中限制Regex输入的指令

时间:2018-01-12 22:10:47

标签: javascript angularjs regex angularjs-directive

我编写了一个角度指令,用于通过指定正则表达式来禁止输入输入。在该指令中,我指出了将用于允许输入数据的正则表达式。从概念上讲,它运行良好,但在此解决方案中有两个错误:

  1. 在第一个Plunker示例中,输入必须允许仅数字数字后跟一个点[。] ,或数字后跟一个点后跟不超过四位的数字
    • 如果我输入值'1.1111',之后我会转到第一个数字,因此输入另一个数字(为了得到一个值 '11 .1111' ),没有任何事情发生。我在我的正则表达式验证器上使用表达式elem.val() + event.key这个错误。我不知道如何获得整体 按键事件输入的当前值;
  2. 第二个是事实上,在打字时允许某些字符(严重,尖锐,波浪形,旋律)(不止一次按下其中一个),但是正则表达式不允许它们。
  3. 我需要在代码中进行哪些更改才能通过正则表达式获得有效的类型限制?

      <html ng-app="app">    
      <head>
        <script data-require="angularjs@1.6.4" data-semver="1.6.4" src="https://code.angularjs.org/1.6.4/angular.min.js"></script>
        <link rel="stylesheet" href="style.css" />
        <script src="script.js"></script>
      </head>
    
      <body>
        <h1>Restrict typing by RegExp</h1>
        PATTERN 1 (^\d+$|^\d+[.]$|^\d+[.]\d{1,4}$) <input type="text" allow-typing="^\d+$|^\d+[.]$|^\d+[.]\d{1,4}$"/><br>
        ONLY NUMBERS <input type="text" allow-typing="^[0-9]+$"/><br>
        ONLY STRINGS <input type="text" allow-typing="^[a-zA-Z]+$"/>
      </body>
    
    </html>
    

    指令

    angular.module('app', []).directive('allowTyping', function() {
      return {
        restrict: 'A',
        link: function(scope, elem, attrs, ctrl) {
          var regex = attrs.allowTyping;
          elem.bind('keypress', function(event) {
            var input = elem.val() + event.key;
            var validator = new RegExp(regex);
            if(!validator.test(input)) {
              event.preventDefault();
              return false;
            }
          });
        }
      };
    });
    

4 个答案:

答案 0 :(得分:1)

如果这是我的代码,我会完全改变策略:我会倾听input个事件,而不是试图微观管理用户与该字段的互动。

一般来说,您采取的方法存在问题。最大的一点是,对于该字段的所有更改,不会发出 keypress值得注意的是,

  1. 它不是由DELETE和BACKSPACE键触发的。

  2. 输入法可以绕过它。当您将变音符号作为变音符号输入时,您的代码未注册更改。通常,如果用户使用input method,则无法保证添加到该字段的每个新字符都会导致keypress事件。这取决于用户选择的方法。

  3. 当用户从字段中剪切或粘贴到字段中时,
  4. keypress无效。

  5. 你可以添加代码来尝试处理上面的所有情况,但它会变得很复杂。您已经遇到elem.val() + event.key的问题,因为keypress可能总是是关于在字段末尾插入的字符。用户可能已移动插入符号,因此您必须跟踪插入符号位置。一条评论建议听keyup,但这对输入法或粘贴/剪切事件没有帮助。

    相反,当字段的值发生变化时,会生成input event。以上所有案例都得到了照顾。例如,这可以起作用:

    elem.bind('input', function(event) {
      var validator = new RegExp(regex);
      elem.css("background-color", !validator.test(elem.val()) ? "red" : null);
    });
    

    这是一个最小的插图,你可以填补你的小提琴来替换你当前的事件处理程序。在一个真实的应用程序中,我会给用户一个详细的错误消息,而不仅仅是改变字段的颜色,我只在事件处理程序之外创建validator一次,但这会给你一个想法。 / p>

    (还有一个change事件,但您不想使用它。对于文本字段,它是在焦点离开字段时生成的,这太迟了。)

答案 1 :(得分:0)

  1. 您在正则表达式中指定了4种不同的模式3个不同的模式,用变更符号分隔:^\d+$|^\d+[.]$|^\d+[.]\d{1,4}$ - 这将不符合input must allow only numbers followed by a dot [.], followed by a number with no more than four digits.错误的标准&#34;没有任何反应&#34;之所以发生,是因为你要检查的变量不是你想象的那样,请查看截图,了解如何检查它,以及它是什么:
  2. enter image description here

    1. 无法复制。

答案 2 :(得分:0)

根据您的方法查看Plnkr Fixed

下面解释原因和变化的解释。 附注:我不会这样实现(将ngModel$parsers$formatters一起使用,例如https://stackoverflow.com/a/15090867/2103767) - 实施超出了您的问题的范围。但是我找到了regexValidate by Ben Lesh的完整实现,它将适合您的问题域: -

  

如果我输入一个值&#39; 1.1111&#39;然后我转到第一个数字,然后键入另一个数字(为了得到一个值为&#39; 11.1111&#39;),没有任何事情发生。

因为在下面的代码中

  

var input = elem.val() + event.key;

您假设event.key总是附加在最后。

那么如何获得正确位置的位置并验证重建的字符串?您可以使用未记录的event.target.selectionStart属性。请注意,即使您没有选择任何内容,您也会填充此内容(IE 11和其他浏览器)。见Plnkr Fixed

  

第二个是事实上,一些字符(严重,尖锐,波浪,旋律)被允许打字(不止一次按下其中一个),虽然正则表达式不允许它们。

修正了正则表达式 - 更正以下内容:

^[0-9]*(?:\.[0-9]{0,4})?$

所以整个事情看起来如下

  link: function(scope, elem, attrs, ctrl) {
    var regex = attrs.allowTyping;
    elem.bind('keypress', function(event) {
      var pos = event.target.selectionStart;
      var oldViewValue = elem.val();
      var input = newViewValue(oldViewValue, pos, event.key);
      console.log(input);
      var validator = new RegExp(regex);
      if (!validator.test(input)) {
        event.preventDefault();
        return false;
      }
    });

    function newViewValue(oldViewValue, pos, key) {
      if (!oldViewValue) return key;
      return [oldViewValue.slice(0, pos), key, oldViewValue.slice(pos)].join('');
    }
  }

答案 3 :(得分:0)

您可以将事件更改为keyup,因此测试将在>添加每个其他字符后运行。

这意味着你需要保存最后一个有效输入,所以如果用户试图插入一个将字符串变为无效的字符,测试将恢复最后一个有效值。

因此,更新的指令:

angular.module('app', [])
    .directive('allowTyping', function()  {
        return {
            restrict : 'A',
            link : function(scope, elem, attrs, ctrl) {
                var regex = attrs.allowTyping;
                var lastInputValue = "";
                elem.bind('keyup', function(event) {
                var input = elem.val();
                var validator = new RegExp(regex);

                if (!validator.test(input))
                    // Restore last valid input
                    elem.val(lastInputValue).trigger('input');
                else
                    // Update last valid input
                    lastInputValue = input;
                });
            }
        };
    });