AngularJS指令正在根据指令名称的第一个字符中断

AngularJS指令正在根据指令名称的第一个字符中断,angularjs,angularjs-directive,Angularjs,Angularjs Directive,我写了一个角度指令,显示出一些奇怪的行为。该指令向$parsers添加了一个函数,以限制用户基于正则表达式模式键入的内容。如果当前文本与模式不匹配,解析器将文本恢复为字段的上一个值 因此,当文本被还原时,Angular会将此检测为字段值的更改,并再次进入解析器。这通常是好的,因为传入解析器的值现在是有效的,但我遇到了一个非常奇怪的怪癖 在这个指令生效后,我决定更改它的名称。我这样做了,突然验证失败了。我的错误处理程序报告了太多的递归。当我调试代码时,我发现输入无效字符后对解析器的第二次调用显示字

我写了一个角度指令,显示出一些奇怪的行为。该指令向$parsers添加了一个函数,以限制用户基于正则表达式模式键入的内容。如果当前文本与模式不匹配,解析器将文本恢复为字段的上一个值

因此,当文本被还原时,Angular会将此检测为字段值的更改,并再次进入解析器。这通常是好的,因为传入解析器的值现在是有效的,但我遇到了一个非常奇怪的怪癖

在这个指令生效后,我决定更改它的名称。我这样做了,突然验证失败了。我的错误处理程序报告了太多的递归。当我调试代码时,我发现输入无效字符后对解析器的第二次调用显示字段值参数为“undefined”。结果,我的代码将该值视为无效,并尝试再次恢复,这导致使用“未定义”值等再次调用解析器,直到发生堆栈溢出

我重新更改了指令名,再次调试,然后一切突然开始正常工作!对解析器的第二次调用具有正确的值,而不是“undefined”

我做了一些尝试,发现我可以通过改变指令名的第一个字符来重新创建这个bug。以“a”到“m”开头的指令名运行良好,但以“n”到“z”开头的名称则失效(好的,我承认,我没有尝试全部26个字符,但字符样本显示,样本中指令名称的第一个字母位于字母表的前半部分的所有名称都有效,而第一个字母位于字母表的后半部分的所有运行都失败)

我将一个plunker与我的代码放在一起演示:

var-app=angular.module('plunker',[]);
应用程序控制器('MainCtrl',函数($scope){
$scope.someNumber;
});
应用程序指令('formattedWithPattern',函数(){
//将输入字段格式化为正整数。
//用法:
//  
//创建:
//  
返回{
要求:'ngModel',
链接:函数(范围、元素、属性、ctrl){
如果(!ctrl)返回;
var模式=attr.ngPattern;
//获取斜线和任何修改器之间的图案
var r=new RegExp(“^/(.*)/(.*)$”;
var matches=r.exec(模式);
var regex;
如果(匹配){
regex=newregexp(“^”+匹配[1]+“$”,匹配[2]);
}
var lastText='';
var恢复=假;
函数fromUser(文本){
var m=regex.exec(文本);
如果(m){
//将匹配项连接到一个字符串中
lastText=m[0];
如果(lastText!=文本){
//原始文本包含一些无效字符
ctrl.$setViewValue(lastText);
ctrl.$render();
}
}
否则{
//文本中没有与正则表达式匹配的内容。。。
//恢复到上一个良好值
如果(文本!=lastText){
ctrl.$setViewValue(lastText);
ctrl.$render();
}
}
返回最新文本;
}
ctrl.$parsers.unshift(fromUser);
}
};
});
下面是一个正在使用的示例(也来自plunker):


{{zip}}
由于某些原因,plunker的行为与我在计算机上测试时看到的略有不同。所有故障仍在字母表的上限范围内,但故障从“o”开始,而不是从“n”开始

如果将app.js和index.html中的指令名称更改为以任何字符“o”到“z”开头,然后重新运行plunker,则可以很容易地看到该行为。上述指令使用数字模式,因此当指令名称为“有效”时,该指令不允许除0-9、、+、和-以外的任何字符。当名称为“invalid”指令还允许使用字符,因为对解析器的递归调用在没有实际更改输入字段值的情况下中断


这让我觉得非常奇怪。我在网上没有发现任何其他关于这一点的提及,所以我想我应该把它扔到这里。还有其他人遇到过类似的事情吗?这是AngularJS中的一个bug吗?除了确保我的指令名以字符a到m开头之外,还有人知道其他工作吗?

你可以提出指令
优先级:
确保执行顺序如下:

return {
  require: 'ngModel',
  priority: 1, // default is 0
  link: function (scope, element, attr, ctrl) {
    ...
  }
};
它将确保在
ng required
ng pattern
之后运行指令postLink功能

示例Plunker:

您还可以直接使用
ctrl.$viewValue
来避免指令执行顺序问题

实际上,IMHO,使用
ctrl.$viewValue
更有意义,因为如果视图无效,您希望重新呈现视图,因此您需要一个真实的视图值,而不是已经传递给其他解析器的值

为此,您可以从以下位置更改解析器:

function fromUser(text) {
  ...
}
对此,请改为:

function fromUser() {
  var text = ctrl.$viewValue;
  ...
}
示例Plunker:


希望这能有所帮助。

我的OormatedWithPattern at似乎做得很好,除非有什么我不明白的地方。我猜:作为解析器的输入得到的是前一个解析器的输出。ng pattern指令还向链中添加了一个解析器,如果输入的文本与模式不匹配,它将输出未定义的。我猜根据名称的不同,解析器放在链中ngPattern的解析器之前或之后
function fromUser(text) {
  ...
}
function fromUser() {
  var text = ctrl.$viewValue;
  ...
}