【问题标题】:How to properly validate attributes of custom directives?如何正确验证自定义指令的属性?
【发布时间】:2015-04-20 19:17:32
【问题描述】:

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

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

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

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

想法?

【问题讨论】:

    标签: angularjs validation angular-directive


    【解决方案1】:

    如果您只需要确保该属性不是可选的并且它引用范围上的有效变量,那么请考虑(再次 - 如果您驳回该想法)将这些属性与隔离范围的 = 一起使用。

    所以你可以指定所需的范围变量:

    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 = 参数[0]; var directiveName = (providerName.match(/(.+)DirectiveProvider$/) || [])[1]; 如果(指令名称){ var _$get = 提供者.$get; console.log(['hi from injector get', arguments[0], provider.$get]); provider.$get = 功能补丁$Get() { var 实例 = _$get.apply(this, arguments); console.log(['hi from provider $get', providerName, instances]); angular.forEach(实例,函数(实例){ 函数 getPatchedPostlink (postlink) { 返回函数 patchedPostlink(scope, element, attrs, ctrls) { var _postlink = 后链接; console.log(['hi from directive link', directiveName, scope, element, attrs, ctrls]); // 这里是 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("作用域变量 '" + scopeVar + "', 指令 '" + directiveName + "' 需要,没有赋值!"); } }); } 返回 angular.isFunction(_postlink) ? _postlink.apply(this, arguments) : undefined; }; } var _compile = instance.compile; // 如果有 'compile' 则 'link' 无效 如果(_编译){ instance.compile = function patchedCompile(element, attrs) { var compile = _compile.apply(实例,参数); console.log(['hi from directive compile', directiveName, this, element, attrs]); 如果(!编译){ 编译 = {}; } else if (angular.isFunction(compile)) { 编译 = { 帖子:编译 }; } // compile.pre = getPatchedPrelink(compile.pre); compile.post = getPatchedPostlink(compile.post); 返回编译; }; } 别的 { instance.link = getPatchedPostlink(instance.link); } }, 这个); 返回实例; }; } 退货提供商; }; }]);

    【讨论】:

    • 我已经这样做了,但是如果我在需要bar 并且定义为隔离范围的= 时使用我的指令就像<my-directive foo="ctrl.foo"></my-directive> 一样会抛出错误吗?我实际上并没有自己测试这个......
    • 我的错,我没有仔细阅读问题。不,它不会抛出它,如果您尝试分配无效的范围变量,它会抛出错误。我已经更新了答案,希望对您有所帮助。
    • 现在这是一个有趣的解决方案 :)
    • 它很冗长,但适用于猴子修补用户定义(但不是 ng)指令。
    【解决方案2】:

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

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

    此外,永远不要假设您的控制器或应用程序总是会在属性中传递有效数据,这样您就可以添加这些检查以使您的代码防弹。

    【讨论】:

      猜你喜欢
      • 2020-04-18
      • 2017-05-26
      • 2014-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多