Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
186 views
in Technique[技术] by (71.8m points)

javascript - AngularJS custom form validation directive doesn't work in my modal

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.

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

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

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.

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...