2015-04-20 62 views
1

說我有這樣的自定義指令:如何正確驗證自定義指令的屬性?

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

會是怎樣的正確方法來驗證這兩個foobar屬性是否有效?我的意思是,它們是指令工作所必需的,我不是指類型驗證。我需要的是驗證屬性是否存在,因爲它對於這個特定的屬性是強制的(不確定是否應該檢查它是否未定義,可能屬於類型驗證)。

是否有任何內置的方法來實現這一目標,或者我將不得不在link函數中自己做到這一點?一個更好的問題可能是,這樣做是否有意義,或者我應該保證我的應用程序正在處理單元測試將特定值傳遞給指令的特定控制器?但是當屬性值是靜態的並且不是來自控制器的範圍時會發生什麼?

想法?

回答

1

不,沒有任何內置驗證可用於屬性。你必須自己做。更清晰的方法是在其中一個必需屬性中的值未定義爲無效時拋出異常。

另一種方式可以簡單地返回所需數據的情況下不會發現拋出異常可能會導致其他問題。

此外,永遠不要假設您的控制器或應用程序總是要傳遞屬性中的有效數據,因此您可以添加這些檢查以使您的代碼具有防彈功能。

2

如果您所需要的只是確保該屬性不是可選的,並且它指向作用域上的有效變量,則可以考慮(再次 - 如果您駁回該想法),使用這些屬性與隔離範圍的=

所以,你可以與指定所需的範圍變量:

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; 
    }; 
}]); 
+0

我這樣做了,不過如果我用我的指令,就像'將拋出一個錯誤<我的指令性富=「ctrl.foo」>''時需要bar'和被定義爲隔離範圍的'='?我其實並沒有自己測試... –

+0

我的不好,我沒有仔細閱讀這個問題。不,它不會拋出它,如果你嘗試分配無效範圍變量,它會拋出一個錯誤。我已經更新了答案,希望它有幫助。 – estus

+0

現在這是一個有趣的解決方案:) –