我编写了一个角度指令,用于通过指定正则表达式来禁止输入输入。在该指令中,我指出了将用于允许输入数据的正则表达式。从概念上讲,它运行良好,但在此解决方案中有两个错误:
elem.val() + event.key
这个错误。我不知道如何获得整体
按键事件输入的当前值; 我需要在代码中进行哪些更改才能通过正则表达式获得有效的类型限制?
<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;
}
});
}
};
});
答案 0 :(得分:1)
如果这是我的代码,我会完全改变策略:我会倾听input
个事件,而不是试图微观管理用户与该字段的互动。
一般来说,您采取的方法存在问题。最大的一点是,对于该字段的所有更改,不会发出 keypress
。值得注意的是,
它不是由DELETE和BACKSPACE键触发的。
输入法可以绕过它。当您将变音符号作为变音符号输入时,您的代码未注册更改。通常,如果用户使用input method,则无法保证添加到该字段的每个新字符都会导致keypress
事件。这取决于用户选择的方法。
keypress
无效。
你可以添加代码来尝试处理上面的所有情况,但它会变得很复杂。您已经遇到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)
答案 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;
});
}
};
});