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

2024-02-29

我编写了一个 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 开头之外,有谁知道解决方法吗?


您可以提出指令priority:确保这样的执行顺序:

return {
  require: 'ngModel',
  priority: 1, // default is 0
  link: function (scope, element, attr, ctrl) {
    ...
  }
};

它将确保您的指令 postLink 函数将在之后运行ng-required and ng-pattern.

笨蛋示例: http://plnkr.co/edit/dy1zCq9F8EejYWo1m4Oe?p=preview http://plnkr.co/edit/dy1zCq9F8EejYWo1m4Oe?p=preview

你也可以使用ctrl.$viewValue直接避免指令执行顺序问题。

实际上,恕我直言,使用ctrl.$viewValue因为如果视图无效,您希望重新渲染视图,因此您需要一个真实的视图值,而不是已经通过其他解析器的值。

为此,您可以将解析器更改为:

function fromUser(text) {
  ...
}

改为:

function fromUser() {
  var text = ctrl.$viewValue;
  ...
}

笨蛋示例: http://plnkr.co/edit/FA2Fq4aNlUrcdUMoopuX?p=preview http://plnkr.co/edit/FA2Fq4aNlUrcdUMoopuX?p=preview

希望这可以帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AngularJS 指令根据指令名称的第一个字符而中断 的相关文章

随机推荐

  • 程序可以读取自己的 elf 部分吗?

    我想使用 ld 的 build id 选项来将构建信息添加到我的二进制文件中 但是 我不确定如何在程序中提供此信息 假设我想编写一个程序 每次发生异常时都会写入回溯 以及一个解析此信息的脚本 该脚本读取程序的符号表并搜索回溯中打印的地址 我
  • 如何获取 Laravel 的平均时间

    我想要得到平均时间开始时间和结束时间之间以及Where CUR Time GroupBY 用户名我在 laravel 中编写了 sql 它显示了一些错误 我找不到那是什么 因为我是 laravel 的新手 请帮助修复此 sql 错误 我提交
  • Android Studio 的启动栏逐渐消失到主程序中

    我目前正在开发一个 Android 应用程序 刚刚开始 我就能够实现我的闪屏了 然而 我不喜欢它和主要活动之间的过渡 我希望初始屏幕淡出 主屏幕淡入 看起来它们混合在一起 因为我对两者都有相同的背景图像 做了一些研究 但未能找到正确的答案
  • 如何将数字转换为科学记数法?

    我想创建一个函数 它接受输入的值并将其转换为科学记数法 N x 10 a 我尝试了很多不同的事情 但我似乎无法做到正确 Example 我输入 200 转换器将其转换为 2 x 10 2 你可以这样做 a 200 a toExponenti
  • 解析错误:语法错误,意外的“mysql_query”(T_STRING)

    我是 php 新手 在更新表的某一列时遇到此错误 if isset POST approved change SELECT FROM workplan forchange mysql query change while infoChang
  • Grails 根据枚举列表属性中的枚举值选择域对象

    我在根据枚举列表中的值从域对象列表中选择项目时遇到问题 我的域对象如下所示 class Truck static hasMany makes Make 其中 Make 看起来像这样 enum Make KENWORTH MACK VOLVO
  • 非托管导出错误“RGiesecke.DllExport.MSBuild.DllExportAppDomainIsolatedTask”

    我在 Visual Studio 2017 编译 DLL 项目时遇到问题 我在包管理器控制台上执行了 Install Package UnmanagedExports 错误 无法从程序集 C Users Tom Desktop CSharp
  • NodeJS ping 端口

    我正在为我工 作的一家托管公司编写一个状态检查器 我们想知道如何使用 nodejs 检查端口的状态 如果可能的话 如果没有 你能建议任何其他想法 比如使用 PHP 和阅读 STDOUT 吗 是的 这可以很容易地使用net http node
  • Java EE 7 属性文件配置的最佳实践建议是什么?

    应用程序配置在现代 Java EE 应用程序中属于什么位置 人们有哪些最佳实践建议 通过应用程序配置 我的意思是诸如与其他设备上的服务的连接设置之类的设置 包括外部设备 例如 Twitter 和我们的内部 Cassandra 服务器 用于主
  • VS2015中如何设置工具提示颜色?

    我刚刚安装了 Visual Studio 2015 总体来说非常好 但是您可以在 工具 gt 选项 gt 字体和颜色 下配置的大量不同内容完全让我感到困惑 我需要找到允许我更改此工具提示颜色的设置 以便我可以实际阅读它 它在哪里 下载颜色主
  • php:: tmp 文件保留多长时间?

    我正在编写上传脚本 如果用户上传一个文件并且该文件已经存在 我想警告用户 这都是通过ajax 并让他们选择替换它或取消 而不是移动文件 我很好奇是否可以将文件保留在 tmp 中并在 ajax 响应中传回该文件的路径 如果用户说覆盖该 aja
  • Android 版 Chrome 无法正确显示 Google 网络字体

    我已经使用 CSS 重现了我遇到的问题font family以及 Android 版 Chrome Web 浏览器无法正确继承字体 而是使用后备字体 http jsbin com iyifah 1 edit http jsbin com i
  • RxJS - 使用成对确认和恢复输入字段

    所以我对可观察的东西有点陌生 我正在努力解决一个场景 我认为它可能是一个很好的候选问题 开始了 场景是这样的 我有一个下拉字段 当它改变时 我想要 检查基于条件以前的值和新的值领域的 如果条件通过 则请求用户确认 并且 如果用户未确认 则恢
  • Android 上的 Bootstrap 3 长模态滚动背景

    我有一个长模态框 无法在我的 Android 移动设备上完全显示 按钮位于屏幕底部下方 模态框根本不滚动 但模态框后面的灰色背景会滚动 是否有任何 css js锁定背景并允许模式在显示时滚动的技巧 可能是因为模态类位置是固定的 尝试将下面的
  • 当某些值丢失时如何绘制谷歌折线图?

    我在以下位置找到了以下 JavaScript 代码谷歌图表工具 http code google com apis chart interactive docs gallery imagelinechart html function dr
  • Colab 上的 gdrive 问题

    安装谷歌驱动器后 我正在使用 colab 在 cifar10 上训练 resnet 我克隆了存储库并且能够运行该脚本 然而 Tensorflow 已加载 数据文件已传递到网络 但我以以下内容结束 tensorflow python fram
  • Java中获取默认根目录

    我正在制作一个基本的文件浏览器 并且想知道如何获取默认根目录 我知道java io File listRoots 给出所有的根 对我来说是A C D E F G H I L T U X Y Z 但我想要用户主要使用的那个 即带有操作系统的那
  • XSD 中缺少响应和 DTO 对象

    我正在使用最新版本的 ServiceStack 和 NuGet 我已经有了一个基本的服务设置 可以与 JsonServiceClient 很好地配合 并且按预期通过了所有单元测试 不幸的是 我还尝试支持 SOAP 和 Visual Stud
  • 适用于 Microsoft Windows 的终端多路复用器 - GNU Screen 或 tmux 的安装程序 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找适用于 Microsoft Windows 的终端多路复用器 我无法找到 tmux 和 GNU Screen 的 Microso
  • AngularJS 指令根据指令名称的第一个字符而中断

    我编写了一个 Angular 指令 该指令表现出一些奇怪的行为 该指令向 parsers 添加了一个函数 以根据正则表达式模式限制用户输入的内容 如果当前文本与模式不匹配 解析器会将文本恢复为该字段的先前值 因此 当文本恢复时 Angula