我编写了一个 Angular 指令,该指令表现出一些奇怪的行为。该指令向 $parsers 添加了一个函数,以根据正则表达式模式限制用户输入的内容。如果当前文本与模式不匹配,解析器会将文本恢复为该字段的先前值。
因此,当文本恢复时,Angular 会将其检测为字段值的更改,并再次进入解析器。这通常很好,因为传递到解析器的值现在是有效的,但我遇到了一个非常奇怪的怪癖。
在该指令发挥作用后,我决定更改其名称。我这样做了,突然验证失败了。我的错误处理程序报告了太多的递归。当我调试代码时,我发现输入无效字符后对解析器的第二次调用显示字段值参数为“未定义”。结果,我的代码将该值视为无效并尝试再次恢复,这导致再次使用“未定义”值等调用解析器,直到发生堆栈溢出。
我把指令名称改回来,再次调试,一切突然开始正常工作!对解析器的第二次调用具有正确的值,而不是“未定义”。
我做了一些尝试,发现可以通过更改指令名称的第一个字符来重新创建此错误。以字符“a”到“m”开头的指令名称工作正常,但以“n”到“z”开头的名称则损坏(好吧,我承认,我没有尝试所有 26 个字符,但字符样本显示示例中指令名称的第一个字母位于字母表的前半部分的所有名称均有效,而第一个字母位于字母表的后半部分的所有运行均失败)。
我将一个 plunker 与我的代码放在一起来演示它:
http://plnkr.co/edit/k8Hpk2jsMCS6xjOKiES5 http://plnkr.co/edit/k8Hpk2jsMCS6xjOKiES5
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.someNumber;
});
app.directive('formattedWithPattern', function () {
// Formats an input field as a positive integer.
// Usage:
// <input type="text" data-integer-format>
// Creates:
// <input type="text" data-integer-format>
return {
require: 'ngModel',
link: function (scope, element, attr, ctrl) {
if (!ctrl) return;
var pattern = attr.ngPattern;
// get the pattern between the slashes and any modifiers
var r = new RegExp("^/(.*)/(.*)$");
var matches = r.exec(pattern);
var regex;
if (matches) {
regex = new RegExp('^' + matches[1] + '$', matches[2]);
}
var lastText = '';
var reverted = false;
function fromUser(text) {
var m = regex.exec(text);
if (m) {
// join matches together into a single string
lastText = m[0];
if (lastText != text) {
// the original text contained some invalid characters
ctrl.$setViewValue(lastText);
ctrl.$render();
}
}
else {
// nothing in the text matched the regular expression...
// revert to the last good value
if (text != lastText) {
ctrl.$setViewValue(lastText);
ctrl.$render();
}
}
return lastText;
}
ctrl.$parsers.unshift(fromUser);
}
};
});
这是一个使用中的示例(也来自 plunker):
<body ng-controller="MainCtrl">
<input type="text" name="testNumber" id="testNumber"
data-ng-model="someNumber" data-ng-required="true"
ng-pattern="/[\+\-]?[0-9]*(\.[0-9]*)?/"
formatted-with-pattern />
{{zip}}
</body>
由于某种原因,该插件的行为与我在计算机上测试时看到的略有不同。所有失败仍然位于字母表的上限范围内,但失败从“o”而不是“n”开始。
如果您将 app.js 和 index.html 中的指令名称更改为以“o”到“z”的任何字符开头,然后重新运行 plunker,您可以轻松地看到该行为。上面的指令使用数字模式,因此当指令名称为“有效”时,指令不允许使用除 0-9、.、+ 和 - 之外的任何字符。当名称“无效”时,该指令还允许使用字符,因为对解析器的递归调用正在爆发,而没有实际更改输入字段值。
这让我觉得非常奇怪的行为。我在网上没有找到任何其他提及此内容的信息,所以我想我将其扔在这里。还有其他人遇到过这样的事情吗?这是 AngularJS 中的一个错误吗?除了确保我的指令名称以字符 a 到 m 开头之外,有谁知道解决方法吗?