tch*_*ist 5 angularjs angularjs-directive
我写了一个 Angular 指令,它表现出一些奇怪的行为。该指令向 $parsers 添加了一个函数,以根据正则表达式模式限制用户键入的内容。如果当前文本与模式不匹配,解析器会将文本恢复为字段的先前值。
结果,当文本被还原时,Angular 会将此检测为字段值的更改并再次进入解析器。这通常很好,因为传递给解析器的值现在有效,但我遇到了一个非常奇怪的怪癖。
在我得到这个指令后,我决定改变它的名字。我这样做了,突然验证失败了。我的错误处理程序报告了太多的递归。当我调试代码时,我发现在输入无效字符后第二次调用解析器将字段值参数显示为“未定义”。结果,我的代码将该值视为无效并尝试再次恢复,这导致再次调用解析器并使用“未定义”值等,直到发生堆栈溢出。
我改回指令名称,再次调试,一切突然开始正常工作!对解析器的第二次调用具有正确的值而不是“未定义”。
我稍微玩了一下,发现我可以通过改变指令名称的第一个字符来重新创建这个错误。以字符 'a' 到 'm' 开头的指令名称工作正常,但以 'n' 到 'z' 开头的名称坏了(好吧,我承认,我没有尝试所有 26 个字符,但字符样本显示样本中指令名称的第一个字母在字母表的前半部分的所有名称都有效,而第一个字母在字母表的后半部分的所有运行都失败了)。
我把一个plunker和我的代码放在一起来演示它:
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);
}
};
});
Run Code Online (Sandbox Code Playgroud)
这是使用中的一个示例(也来自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>
Run Code Online (Sandbox Code Playgroud)
出于某种原因,plunker 的行为与我在计算机上测试时看到的略有不同。所有失败仍然在字母表的上限范围内,但失败从“o”而不是“n”开始。
如果您将 app.js 和 index.html 中的指令名称更改为以任何字符“o”到“z”开头,然后重新运行 plunker,您可以很容易地看到行为。上述指令使用数字模式,因此当指令名称为“有效”时,指令不允许使用除 0-9、.、+ 和 - 之外的任何字符。当名称为“无效”时,指令还允许字符,因为对解析器的递归调用在没有实际更改输入字段值的情况下中断。
这让我觉得非常奇怪的行为。我没有在网上找到任何其他提到的内容,所以我想我会把它扔在这里。有没有其他人遇到过这样的事情?这是 AngularJS 中的错误吗?除了确保我的指令名称以字符 a 到 m 开头之外,有没有人知道其他解决方法?
您可以提出一个指令priority:来确保执行顺序,如下所示:
return {
require: 'ngModel',
priority: 1, // default is 0
link: function (scope, element, attr, ctrl) {
...
}
};
Run Code Online (Sandbox Code Playgroud)
它将确保您的指令 postLink 函数将在ng-required和后运行ng-pattern。
示例 Plunker: http://plnkr.co/edit/dy1zCq9F8EejYWo1m4Oe ?p=preview
您也可以直接使用ctrl.$viewValue以避免指令执行顺序问题。
实际上,恕我直言,使用 更有意义,ctrl.$viewValue因为如果视图无效,您希望重新渲染视图,因此您需要一个真正的视图值,而不是已经通过其他解析器的值。
为此,您可以将解析器更改为:
function fromUser(text) {
...
}
Run Code Online (Sandbox Code Playgroud)
改为:
function fromUser() {
var text = ctrl.$viewValue;
...
}
Run Code Online (Sandbox Code Playgroud)
示例 Plunker: http://plnkr.co/edit/FA2Fq4aNlUrcdUMoopuX ?p=preview
希望这可以帮助。
| 归档时间: |
|
| 查看次数: |
1026 次 |
| 最近记录: |