添加ng-pattern属性的指令

时间:2014-04-02 21:34:20

标签: angularjs angularjs-directive

我正在尝试创建一个将使用ng-pattern属性替换自身的指令。该属性应用于输入元素,但此后元素基本上变得不可用。我无法再在文本框中输入字符。

这是plunkr http://plnkr.co/edit/F6ZQYzxd8Y04Kz8xQmnZ?p=preview

我想我必须在添加属性后错误地编译元素。

app.directive('passwordPattern', ['$compile', function($compile){
    return{
    compile: function (element, attr){

        element.removeAttr('password-pattern');
        element.attr('ng-pattern', '/^[\\w\\S]{6,12}$/');

        return {
            pre: function preLink(scope, iElement, iAttrs, controller) {  },
            post: function postLink(scope, iElement, iAttrs, controller) {
                $compile(iElement)(scope);
            }
        };
    }
};
}]);

对解决方案的任何想法或文本框变得无法使用的原因都将非常值得赞赏。感谢。

2 个答案:

答案 0 :(得分:10)

除了priority: 1000之外,您还需要添加terminal: true

问题是没有 terminal: trueinput指令被编译两次,并且添加了2组更改侦听器,这会引发ngModel有点指示逻辑。

第一次编译Angular执行时看不到ng-pattern,因此输入指令不会将validateRegex解析器添加到其解析器列表中。但是,第二次编译(通过您的$compile(iElement, scope))会看到ng-pattern add validateRegex解析器。

当您在输入框中输入3时,请输入first change listener is called并查看号码3。由于未应用ng-pattern(这会添加validateRegex $parser),因此不存在$parsers,模型会立即更新为3

但是,当第二个更改侦听器被调用时,它会看到ng-pattern并调用validateRegexcalls ngModel.$setValidity('pattern', false)returns {{1} (因为模型永远不应该设置为无效值)。以下是undefined指令内的踢球者,因为ngModel的{​​{1}}以及$viewValue的新3out of sync ,Angular调用输入指令的value函数,updates the input为空。因此,当您在输入框中输入undefined(或任何内容)时,它会立即删除,并且似乎已被破坏。

$render(如3)和priority会阻止输入指令(除非你有一个1000,否则很可能是其他指令从第一次编译。这很好,因为你想要输入指令来考虑ng-pattern - 而不是没有它。您不希望将多组更改侦听器添加到同一元素中,或者它可能(并且会)导致奇怪的副作用。

答案 1 :(得分:0)

另一种解决方案是覆盖pattern控制器中$validators对象的ngModel属性。

您可以在ngModelController docs

中查看验证程序功能的示例

以下是指令中的示例:

angular.module('mymodule')
    .directive('mydirective', MyDirective);

function MyDirective() {
    return {
        restrict: 'A',
        require: 'ngModel',
        scope: {},
        link: function(scope, element, attrs, ngModelController) {
            ngModelController.$validators["pattern"] = validatePattern;

            function validatePattern(modelValue, viewValue) {
                var value = modelValue || viewValue;
                return /[0-9]+/.test(value);
            }
        }
    }
}

您可以修改上面的示例以从外部范围接收模式,并使用模式上的scope.$watch更改验证功能。