Подтвердить что ты не робот

Могу ли я программно применять директивы валидации w50 в пользовательской директиве?

Я нашел много примеров следующего шаблона для входов html, это для телефонных номеров:

<input type="text" ng-model="CellPhoneNumber" required ng-pattern="/^[0-9]+$/" ng-minlength="10" />

Я хотел бы создать настраиваемую директиву, которая, когда будет применена, сообщит Angular применить все три этих правила, например:

<input type="text" ng-model="CellPhoneNumber" bk-ng-validation="phoneNumber"/>

Тогда код в моей директиве найдет и вызовет функцию под названием phoneNumber, в которой я хотел бы увидеть что-то вроде:

Листинг 1:

function bkNgPhoneNumber(model) {
    // This is purely SPECULATIVE pseudo-code, just to convey an idea.
    model.errors.add(applyMinLength(10, model));
    model.errors.add(applyMaxLength(15, model));
    model.errors.add(applyPattern("/^[0-9]+$/", model));
}

Я предпочел бы вышеупомянутый подход по поводу "переписывания кода для этих правил, например:

Листинг 2:

function phoneNumber(model) {
    if (model.length < 10 || model.length > 15) {
        model.errors.add("Must be 10 to 15 chars!");
    }
}

Я не хочу избавляться от всех директив, основанных на атрибутах, но предпочтительно создавать директиву "macro", которая будет вызывать мой код листинга 1, который будет использоваться для вызова нескольких более "микро" проверок.

4b9b3361

Ответ 1

Один из способов сделать это (т.е. применить существующие валидаторы без повторного написания кода) - это добавить соответствующие атрибуты директив проверки и принудительно перекомпилировать. Это потребует, чтобы ваша директива имела высокий приоритет, а также terminal: true.

app.directive("bkNgValidation", function($compile){
  return {
    priority: 10000,
    terminal: true,
    link: function(scope, element){
      element.attr("ng-required", "true");
      element.attr("ng-minlength", 20);
      element.attr("ng-maxlength", 30);

      // prevent infinite loop
      element.removeAttr("bk-ng-validation");

      $compile(element)(scope);
    }
  };
});

Демо

Ответ 2

Если вы используете больше проверок, вы можете создать службу, которая отвечает за идентификацию и проверку элементов без каких-либо ограничений. Директивы по умолчанию angular остаются.

Пример:

    module.service('$Validation', ["$compile",function($compile){

        this.validators = {
            'phoneNumber': [['required', 1], ['minlength',6], ['maxlength', 10], ['pattern', /^[0-9]+$/.source]],
            'phoneNumber2Custom': function(value){ 
                return /^[0-9]{6,10}$/.test(value) 
            },
            'userTwitter': function(value){
                return /^@(.+)/.test(value)
            }
            // ...etc... /
        }

        this.add = function(scope, element, attrs, model){
            var name = attrs.bkNgValidation, type;
            if(!(type = this.validators[name])) return;
            else if(angular.isFunction(type)) return (model.$validators[name] = type);

            element.removeAttr("bk-ng-validation");
            angular.forEach(type, function(expr){
                element.attr(expr[0], expr[1])
            });
            $compile(element)(scope)        
        };

    }]).directive('bkNgValidation', ["$Validation", function ($Validation) {
        return {
            require: '?ngModel',
            priority: 1e5,
            link: function(){
                $Validation.add.apply($Validation, arguments);
            }
        }
    }])

Демо

Ответ 3

Вы можете попробовать этот подход:

.directive('bkNgValidation', function () {
  return: {
    link: function (scope, element, attrs) {
      if (attrs['bk-ng-validation'] === 'phoneNumber') {
       element.$validateModel(function (value, validator) {
         if (value.length < 10 || value.length > 15) {
           validator.$setValidity('phone', true);
         } else {
           validator.$setValidity('phone', false);
         }
       });
      }
    }
  }
})

Ответ 4

Вы можете создать новый компонент, который включает элемент управления со всеми необходимыми валидаторами. Ваш компонент будет выглядеть так:

<my-control name="field" ng-model="text"></my-control>

Все необходимые логические компоненты должны храниться внутри. Для этого создайте директиву my-control с шаблоном. Внутри шаблона вы можете поместить ввод с атрибутами проверки:

<input type="text" ng-model="value" class="form-control" ng-pattern="'^(?!ng-*)'" minlength="3">

Затем вам нужно привязать значение ng-модели к вашему компоненту для ввода:

angular.module('app', []).directive('myControl', function() {
   return {
       restrict: 'E',
       require: 'ngModel', //import ngModel into linking function
       templateUrl: 'myControl.tpl',
       scope: {}, //our component can have private properties, isolate it
       link: function(scope, elm, attrs, ngModel) {
           // reflect model changes via js
           ngModel.$render = function() {
               scope.value = ngModel.$viewValue;
           };
           // update model value after changes in input
           scope.$watch('value', function(value) {
               ngModel.$setViewValue(value);
           });
       }
   };
});

Вот демон когда вы видите этот компонент в действии и как он работает.

Ответ 5

Вы идете в обратном направлении, потому что вы предполагаете, что директивы настолько трудоемки, что они поддерживают, и хотят, чтобы они давали всю необходимую валидацию в зависимости от элемента.

Это интересный подход, но вы должны быть предупреждены о модульности этого подхода: отдайте эту большую часть труда одной директиве, но это не противоречит лучшим методам "чистого" способа w500, чтобы делать что-то.

Если вы хотите продолжить эту идею, я предлагаю вам просмотреть свойства ngModelController (AngularJS Docs), которые могут быть вводится в функцию link() одной директивы. Точнее, $validators.

Вы можете добавить, сколько $validators к контроллеру NgModel вы хотите.

Во время проверки вы можете установить/отключить действительность для элемента, возвращающего логическое значение:

app.directive('validator', function () {
    var definition = {
        restrict: 'A',
        require: '?ngModel',
        link: function (scope, element, attrs, ngModel) {
            // Return if no ngModelController
            if (!ngModel) {
                return;
            }

            ngModel.$validators.validateLength = function (modelValue, viewValue) {
                // modelValue === the value of the ngModel, on the script side
                // viewValue === the value of the ngModel, on the HTML (rendered) side
                // 
                // you can set-up $parsers, $formatters, $validators, etc, to handle the element

                return !(modelValue.length > 20);
            }
        }
    };

    return definition;
});

Я предлагаю вам больше узнать об этой реализации, потому что некоторые операции могут прерывать поток циклов $digest на Angular над управляемым элементом.

Изменить 1:

Как я уже упоминал в комментариях, здесь Plunkr с рабочим примером.