如何正确验证自定义指令的属性?

时间:2015-04-20 19:17:32

标签: angularjs validation angular-directive

假设我有这样的自定义指令:

<my-directive foo="ctrl.foo" bar="ctrl.bar"></my-directive>

验证foobar属性是否有效的正确方法是什么?我的意思是,它们是指令工作所必需的,我不是指类型验证。我需要的是验证属性是否存在,因为它对于这个特定属性是强制性的(不确定我是否应该检查它是否未定义,可能属于类型验证)。

是否有任何内置方法可以实现这一点,还是我必须自己在link函数中执行此操作?一个更好的问题可能是,甚至做到这一点是否有意义,或者我应该保证我的应用程序正在使用单元测试将特定控制器传递给指令的特定控制器?但是当属性值是静态的并且不是来自控制器的范围时会发生什么?

思想?

2 个答案:

答案 0 :(得分:2)

如果您只需要确保该属性不是可选的并且它引用了范围上的有效变量,那么请考虑(再次 - 如果您认为这个想法)使用这些属性与隔离范围=。< / p>

因此,您可以使用以下命令指定所需的范围变量:

scope: { requiredVar: '=requiredAttribute' },
scopeRequired: [ 'requiredVar' ],

link是修改行为的好地方,因为它涉及范围,并且(如果它嵌套在compile中)它可以从中获取对this.scopeRequired的引用。

当然,您可以在每个指令的基础上执行此操作,但如果您希望将其作为全局行为...这是我用来闯入指令的方法。

app.config(['$injector', function ($injector) {
  var _get = $injector.get;

  $injector.get = function patchedGet() {
    var provider = _get.apply(this, arguments);

    var providerName = arguments[0];
    var directiveName = (providerName.match(/(.+)DirectiveProvider$/) || [])[1];
    if (directiveName) {
      var _$get = provider.$get;
      console.log(['hi from injector get', arguments[0], provider.$get]);

      provider.$get = function patched$Get() {
        var instances = _$get.apply(this, arguments);
        console.log(['hi from provider $get', providerName, instances]);

        angular.forEach(instances, function(instance) {

          function getPatchedPostlink (postlink) {
            return function patchedPostlink(scope, element, attrs, ctrls) {
              var _postlink = postlink;
              console.log(['hi from directive link', directiveName, scope, element, attrs, ctrls]);

              // here it goes
              if (scope.$$isolateBindings && instance.scopeRequired) {
                var bindings = scope.$$isolateBindings;
                angular.forEach(instance.scopeRequired, function (scopeVar) {
                  if (!bindings[scopeVar] || !attrs.hasOwnProperty(bindings[scopeVar].attrName)) {
                    throw new Error("Scope variable '" + scopeVar + "', required by directive '" + directiveName + "', wasn't assigned!");
                  }
                });
              }

              return angular.isFunction(_postlink) ? _postlink.apply(this, arguments) : undefined;
            };
          }

          var _compile = instance.compile;

          // 'link' is impotent if there is 'compile'
          if (_compile) {
            instance.compile = function patchedCompile(element, attrs) {
              var compile = _compile.apply(instance, arguments);
              console.log(['hi from directive compile', directiveName, this, element, attrs]);

              if (!compile) {
                compile = {};
              } else if (angular.isFunction(compile)) {
                compile = { post: compile };
              }
              // compile.pre = getPatchedPrelink(compile.pre);
              compile.post = getPatchedPostlink(compile.post);
              return compile;
            };
          } else {
            instance.link = getPatchedPostlink(instance.link);
          }
        }, this); 
        return instances;
      };
    }
    return provider;
  };
}]);

答案 1 :(得分:1)

不,没有任何可用于属性的内置验证。你必须自己做。更简洁的方法是在其中一个必需属性中的值未定义无效时抛出异常。

另一种方法可以是在没有找到所需数据的情况下简单返回,因为抛出异常可能会导致其他问题。

此外,永远不要假设您的控制器或应用程序始终在属性中传递有效数据,以便您可以添加这些检查以使您的代码成为子弹证明。