0

I am writing a directive which will be used to establish client and server-side validation on an input. It should accept an array of validator names (e.g. aa-validate="required,unique"), loop through them, add client-side validation directives for all possible validators (e.g. required should add ngRequired), and for the rest, post to a server-side validation API.

The last part of that works well: I am watching the ngModel attribute, and posting to the server with a 100ms timeout. However, setting client-side validation directives from within the linking function of my directive does NOT cause them to be compiled and linked. In other words, they do nothing. Here is my code:

angular.module('form', [])
    .directive('aaValidate', ['$http', function($http) {
        return {
            priority: 1,
            restrict: 'A',
            require: 'ngModel',
            link: function(scope, element, attrs, ctrl) {
                var validate = attrs.aaValidate,
                    validators = validate.split(',');

                // This is the problem!
                //
                // Populate possible client-side validators
                for (var i = 0, len = validators.length; i < len; i++) {
                    var validator = validators[i];
                    switch (validator) {
                        case 'required':
                            attrs.$set('ngRequired', 'true'); break;
                        // ... and so on for ngPattern, etc.
                        default: break;
                    }
                }

                scope.$watch(attrs.ngModel, function(value) {
                    // This part works!
                    //
                    // Clear existing timeout, reset it with an
                    // $http.post to my validation API, the result is
                    // passed into ctrl.$setValidity
                });
            }
        }
    }]);

I did make an attempt to inject $compile, and re-compile the element at the end of the linking function. I ended up with infinite recursion, likely because I failed to remove some attributes, but even if I manage to do it this way, it feels rather ugly. What is the correct approach?

Any help is greatly appreciated. Thanks in advance.


EDIT: jsFiddle: http://jsfiddle.net/3nUdj/4/

4

1 回答 1

1

我的第一个答案是错误的——我认为没有任何办法可以使用该$compile服务。以下是如何在没有无限递归的情况下做到这一点。我基本上将指令分为两个指令 - 一个添加验证指令,删除自身并重新编译。另一个做其他事情:

angular.module('form', [])
.directive('aaValidate', ['$http', '$compile', function ($http, $compile) {
  return {
    link: function (scope, element, attrs) {
      var validate = attrs.aaValidate,
          validators = validate.split(',');

      // Populate possible front-end validators
      for (var i = 0, len = validators.length; i < len; i++) {
        var validator = validators[i];
        switch (validator) {
          case 'required':
            attrs.$set('ngRequired', 'true');
            break;
          default:
            break;
        }
      }
      attrs.$set('aaOther', '');
      element.removeAttr('aa-validate');
      $compile(element)(scope);
    }
  }
}])

.directive('aaOther', function () {
    return {
      require: 'ngModel',
      link: function (scope, element, attrs, ctrl) {
        scope.$watch(attrs.ngModel, function (value) {
          // Server-side validation
        });
      }
    }
});

您必须重新编译链接的元素才能在 ng-repeat 中工作。我已经更新了小提琴:http: //jsfiddle.net/3nUdj/7/

于 2013-05-24T19:06:48.797 回答