7

I would like to create a wrapper for my input field with an input-help tool tip inside of it.

I am using angular 1.0.7, if it's significant.

I'm using transclude: true, along with isolate scope in order to allow errors at several different fields simultaneously, and still maintain the ng-model reference to the external $scope.

The Problem:

when I use this directive on the input element, the input element doesn't clone('Transclude') into the directive template.

As a result of that I am getting an empty div element at the DOM, with an ng-transclude attribute.

plunk: http://plnkr.co/edit/vFB9ih6x2NBmwhAes3Qh?p=preview

code:

<input data-my-validate-input data-value-required="true" type="password" class="loginItem" placeholder="Password" name="password" data-ng-model="formData.password" data-display-name="Password">

However when I wrap this input element in a span or div, the child input element is transcended just fine, but then I don't get the a reference to the correct external ng-model(ctrl) at the directive.

<span data-my-validate-input data-value-required="true" data-display-name="Password">
      <input type="password" class="loginItem" placeholder="Password" name="password" data-ng-model="formData.password" >    
</span>

Full code(the logic inside the link function is not relevant to the problem, but I preferred to post my full code)

directive('myValidateInput', function() {
    return {
        require: 'ngModel',
          restrict: 'A',
          transclude: true,
          scope: {
            displayName: '@',
            valueRequired: '@',
            maxLength: '@',
            minLength: '@',
            minLetters: '@',
            minNumbers: '@'
          },
          template: '<div class="validationContainer">\
                      <div ng-transclude></div>\
                      <div class="input-help">\
                        <h4>{{fieldErrorDisplay}}</h4>\
                        <ul>\
                          <li data-ng-repeat="rule in requirementSpec" ng-class="rule.class">\
                              {{rule.msg}}\
                          </li>\
                        </ul>\
                      </div>\
                    </div>',
         replace: true,
         link: function(scope, elm, attrs, ctrl) {
                 var validator = function(viewValue){
                          if(scope.valueRequired && viewValue.length == 0 && (!scope.maxLength && !scope.minLength && !scope.minLetters && !scope.minNumbers)){
                    scope.valid = false;  
                    scope.fieldErrorDisplay = scope.fieldName + ' is required';
                  }
                  else{
                        scope.fieldErrorDisplay = scope.fieldName + ' must meet the following requirements: ';
                        scope.requirementSpec = [];
                        if(scope.minLength){
                          var itemValidity = viewValue.length >= scope.minLength;
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' : 'Must be at least ' + scope.minLength + ' characters long',
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                        else if(scope.valueRequired){
                          var itemValidity = viewValue && viewValue.length >= 1;
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' : 'This field must be filled',
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                        if(scope.maxLength){
                          var itemValidity = viewValue.length <= scope.maxLength;
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' : 'Must be ' + scope.maxLength + ' characters long at most  ',
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                        if(scope.minLetters){
                          var itemValidity = (viewValue && /[A-z]/.test(viewValue));
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' : 'Must contain at least ' + scope.minLetters + ' letters',
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                        if(attrs.minNumbers){
                          var itemValidity = (viewValue && /\d/.test(viewValue));
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' : 'Must contain at least' + attrs.minNumbers + ' numbers',
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                  }

                  if(scope.valid) {
                      ctrl.$setValidity(nameStr, true);
                      return viewValue;
                  } else {
                      ctrl.$setValidity(nameStr, false);                    
                      return undefined;
                  }
             }

             scope.requirementSpec = {};

             ctrl.$parsers.unshift(function(viewValue) {
               return validator(viewValue);
             });
             ctrl.$formatters.unshift(function(viewValue) {
               // var before = scope.$eval(attrs.validateBefore);
               if(viewValue && viewValue != "" && viewValue.length > 0)
                 return validator(viewValue);

             });


        });
    }
});
2

1 Answer 1

3

The solution: $transclude only takes the compiled content of the element, thus not the element it self.

Obviously I lack the understanding of this significant detail in my implementation.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.