AngularJS自定义表单验证指令在我的模式中不起作用

时间:2021-12-07 07:10:45

I decided to write a custom directive to help me validate my input boxes. The idea is that I add my new fancy nx-validate directive to a bootstrap div.form-group and it'll check whether my <input/> is $dirty or $invalid and apply the .has-success or .has-error class as required.

我决定编写一个自定义指令来帮助我验证输入框。我的想法是将新的nx-validate指令添加到bootstrap div.form-group中,它将检查我的是$dirty还是$invalid,并根据需要应用.has-success或.has-error类。

For some odd reason, my directive works perfectly under normal circumstances, but the added ng-class is completely ignored inside a ui-bootstrap modal.

由于某些奇怪的原因,我的指令在正常情况下可以完美地工作,但是在ui-bootstrap模式中,添加的ng类完全被忽略。

Identical code in both the modal and the form

模态代码和形式代码相同

<form name="mainForm">
  <div class="row">
      <div nx-validate class="form-group has-feedback col-lg-6 col-md-6 col-xs-12">
          <label class="control-label">Green if long enough, red if not</label>
          <input type="text" id="name" class="form-control" ng-model="property.name" required="required" ng-minlength="5"/>
          (once touched I do change colour - happy face)
      </div>
  </div>        

And my lovely directive

和我可爱的指令

nitro.directive("nxValidate", function($compile) {
    return {
        restrict: 'A',
        priority: 2000,
        compile: function(element) {

            var node = element;
            while (node && node[0].tagName != 'FORM') {
                console.log (node[0].tagName)
                node = node.parent();
            }
            if (!node) console.error("No form node as parent");
            var formName = node.attr("name");
            if (!formName) console.error("Form needs a name attribute");


            var label = element.find("label");
            var input = element.find("input");
            var inputId = input.attr("id")

            if (!label.attr("for")) {
                label.attr("for", inputId);
            }

            if (!input.attr("name")) {
                input.attr("name", inputId);
            }

            if (!input.attr("placeholder")) {
                input.attr("placeholder", label.html());
            }

            element.attr("ng-class", "{'has-error' : " + formName + "." + inputId + ".$invalid && " + formName + "." + inputId + ".$touched, 'has-success' : " + formName + "." + inputId + ".$valid && " + formName + "." + inputId + ".$touched}");
            element.removeAttr("nx-validate");

            var fn = $compile(element);

            return function($scope) {
                fn($scope);
            }

        }
    }
});

Check it out on plunker: http://plnkr.co/edit/AjvNi5e6hmXcTgpXgTlH?

在plunker: http://plnkr.co/edit/ajvni5e6hmxctxgtlh?

1 个解决方案

#1


3  

The simplest way I'd suggest you is you can put those classes by using watch on those fields, this watcher will lie inside the postlink function after compiling a DOM

我建议您的最简单的方法是,您可以通过在这些字段上使用watch来放置这些类,在编译DOM之后,这个监视程序将位于postlink函数中

return function($scope, element) {
    fn($scope);

    $scope.$watch(function(){
      return $scope.modalForm.name.$invalid && $scope.modalForm.name.$touched;
    }, function(newVal){
      if(newVal)
        element.addClass('has-error');
      else
        element.removeClass('has-error');
    })

    $scope.$watch(function(){
      return $scope.modalForm.name.$valid && $scope.modalForm.name.$touched;
    }, function(newVal){
      if(newVal)
        element.addClass('has-success');
      else
        element.removeClass('has-success');
    })
}

Demo Here

演示

Update

更新

The actual better way of doing this would be instead of compiling element from compile, we need $compile the element from the link function itself. The reason behind the compiling DOM in link fn using $compile is that our ng-class attribute does contain the scope variable which is like myForm.name.$invalid ,so when we $compile the DOM of compile function then they are not evaluating value of myForm.name.$invalid variable because compile don't have access to scope & the would be always undefined or blank. So while compile DOM inside the link would have all the scope values are available that does contain myForm.name.$invalid so after compiling it with directive scope you will get your ng-class directive binding will work.

这样做的更好方法是不从编译中编译元素,而是需要从link函数本身编译元素。编译DOM的原因使用美元编译链接fn ng-class属性包含范围变量,就像myForm.name。美元是无效的,所以当我们编译编译函数的DOM美元然后他们不是myForm.name评价值。$无效变量因为编译没有访问范围&就总是定义或空白。因此,虽然在链接内编译DOM时,所有包含myForm.name的作用域值都是可用的,$invalid所以在使用指令作用域编译它之后,您将得到您的ng类指令绑定。

Code

代码

compile: function(element) {
    //..other code will be as is..

    element.removeAttr("nx-validate");
      //var fn = $compile(element); //remove this line from compile fn
      return function($scope, element) {
         //fn($scope);
         $compile(element)($scope); //added in postLink to compile dom to get binding working
      }
 }

Updated Plunkr

更新Plunkr

#1


3  

The simplest way I'd suggest you is you can put those classes by using watch on those fields, this watcher will lie inside the postlink function after compiling a DOM

我建议您的最简单的方法是,您可以通过在这些字段上使用watch来放置这些类,在编译DOM之后,这个监视程序将位于postlink函数中

return function($scope, element) {
    fn($scope);

    $scope.$watch(function(){
      return $scope.modalForm.name.$invalid && $scope.modalForm.name.$touched;
    }, function(newVal){
      if(newVal)
        element.addClass('has-error');
      else
        element.removeClass('has-error');
    })

    $scope.$watch(function(){
      return $scope.modalForm.name.$valid && $scope.modalForm.name.$touched;
    }, function(newVal){
      if(newVal)
        element.addClass('has-success');
      else
        element.removeClass('has-success');
    })
}

Demo Here

演示

Update

更新

The actual better way of doing this would be instead of compiling element from compile, we need $compile the element from the link function itself. The reason behind the compiling DOM in link fn using $compile is that our ng-class attribute does contain the scope variable which is like myForm.name.$invalid ,so when we $compile the DOM of compile function then they are not evaluating value of myForm.name.$invalid variable because compile don't have access to scope & the would be always undefined or blank. So while compile DOM inside the link would have all the scope values are available that does contain myForm.name.$invalid so after compiling it with directive scope you will get your ng-class directive binding will work.

这样做的更好方法是不从编译中编译元素,而是需要从link函数本身编译元素。编译DOM的原因使用美元编译链接fn ng-class属性包含范围变量,就像myForm.name。美元是无效的,所以当我们编译编译函数的DOM美元然后他们不是myForm.name评价值。$无效变量因为编译没有访问范围&就总是定义或空白。因此,虽然在链接内编译DOM时,所有包含myForm.name的作用域值都是可用的,$invalid所以在使用指令作用域编译它之后,您将得到您的ng类指令绑定。

Code

代码

compile: function(element) {
    //..other code will be as is..

    element.removeAttr("nx-validate");
      //var fn = $compile(element); //remove this line from compile fn
      return function($scope, element) {
         //fn($scope);
         $compile(element)($scope); //added in postLink to compile dom to get binding working
      }
 }

Updated Plunkr

更新Plunkr