Директива пользовательского валидатора Angular, нарушающая другие директивы

Я пытаюсь создать директиву для полей ввода, которая проверяет использование пользовательской функции, переданной из внешней области, например:

HTML:

<input type="text" custom-validator="checkValidity"/>

Контроллер:

$scope.checkValidity = function(value){
    return $scope.invalidWords.indexOf(value) === -1;
}

Для этого я создал подробный планкер: http://plnkr.co/edit/H5A5O3?p=preview

Проверка работает, но, похоже, она не работает с директивами по умолчанию, в этом случае ng-disabled не работает, и я не могу получить доступ к переменной, используемой в ng-model!

Это моя директива:

app.directive('customValidator', function() {   
   return {
      require: "ngModel"
    , scope: { customValidator: '='}
    , link: function postLink(scope, elm, attrs, ctrl) {
          var validator = function(value) {
            if(scope.customValidator && scope.customValidator(value)) {
              ctrl.$setValidity('custom-validator', true);
              return value;
            }
            ctrl.$setValidity('custom-validator', false);
            return undefined;
          }
          ctrl.$parsers.unshift(validator);
          ctrl.$formatters.unshift(validator);
        }      
   } 
});

Я не могу понять, что происходит, мне очень нужна помощь!

Я должен остаться на Angular 1.0.7


person destegabry    schedule 21.08.2013    source источник


Ответы (2)


Причина, по которой ng-disabled не работает над inputB, заключается в том, что вы создаете новую область действия с помощью своей директивы:

scope: { customValidator: '=' }

Чтобы сохранить вашу модель inputB в той же области, что и inputA, вы можете сделать что-то вроде этого:

app.directive('customValidator', function() {
    return {
        require: "ngModel", 
        scope: false, 
        link: function postLink(scope, elm, attrs, ctrl) {
            var validator = function(value) {
                customValidator = scope[attrs["customValidator"]];  
                if(customValidator(value)) {
                    ctrl.$setValidity('custom-validator', true);
                    return value;
                }
                ctrl.$setValidity('custom-validator', false);
                return undefined;
            }
            ctrl.$parsers.unshift(validator);
            ctrl.$formatters.unshift(validator);
        }   
    }
});
person AlwaysALearner    schedule 21.08.2013
comment
Это сработало бы, но я не смог передать пользовательскую функцию. В моем случае я должен использовать 3 разные функции для ввода 3 форм. Я пробовал transclude: true, но, похоже, это не исправить... - person destegabry; 21.08.2013
comment
@destegabry Взгляните на мою обновленную директиву, в которой используется attrs. - person AlwaysALearner; 21.08.2013
comment
+1, но я думаю, что использование $parse немного чище (см. мой ответ). - person Mark Rajcok; 21.08.2013
comment
@MarkRajcok Я полностью с тобой согласен. +1 :) - person AlwaysALearner; 22.08.2013

ng-model и изолировать области плохо сочетаются, поэтому следуйте @Codezilla Совет и не создавайте новую область.

Однако я предлагаю использовать $parse, что позволяет нам четко указать в HTML, что мы передаем функцию с одним (именованным) аргументом в директиву:

<input type="text" ... custom-validator="checkValidity(val)">

app.directive('customValidator', function($parse) {
    return {
        require: "ngModel", 
        //scope: false, 
        link: function postLink(scope, elm, attrs, ctrl) {
            var validationFn = $parse(attrs.customValidator);
            var validator = function(value) {
                if(validationFn(scope, {val: value})) {
                    ctrl.$setValidity('custom-validator', true);
                    return value;
                }
                ctrl.$setValidity('custom-validator', false);
                return undefined;
            }
            ctrl.$parsers.unshift(validator);
            ctrl.$formatters.unshift(validator);
        }   
    }
});

plunker

person Mark Rajcok    schedule 21.08.2013