0

I am having a problem with the dynamic creation of a Form. I have a directive that gets set against a form element. It uses Jquery to get the element by id. However it seems that it has not yet been added to the DOM.

            <form class="form-horizontal">
            <div class="control-group" ng-repeat="field in viewModel.fields">
                <label class="control-label">{{field.label}}</label>
                <div class="controls" ng-switch="field.type">
                    <input ng-switch-when="text" type="text" id="{{field.label}}" ng-model="field.data" validator="viewModel.validator"  ruleSetName="personFirstNameRules"/>
                    <span ng-switch-when="text" validation-Message-For="{{field.label}}"></span>
                </div>
            </div>

            <button ng-click="testID()">Submit</button>
        </form>

If I hard code the ID attribute for the text field and on the span element validation-Message-For then their is no issue.The area where i am getting undefined is

    var errorElementController = angular.element(errorElement).controller('ngModel');
    var validatorsController = angular.element(errorElement).controller('validator');

The full directive is here

(function (angular, $) {

angular.module('directivesModule')
       .directive('validationMessageFor', [function () {
           return {
               link: function (scope, element, attributes) {
                   var errorElementId = attributes.validationMessageFor;
                   if (!errorElementId) {
                       return;
                   }
                   var areCustomErrorsWatched = false;

                   var watchRuleChange = function (validationInfo, rule) {
                        scope.$watch(function () {
                             return validationInfo.validator.ruleSetHasErrors(validationInfo.ruleSetName, rule.errorCode);
                        }, showErrorInfoIfNeeded);
                   };

                   var watchCustomErrors = function (validationInfo) {
                       if (!areCustomErrorsWatched && validationInfo && validationInfo.validator) {
                           areCustomErrorsWatched = true;
                           var validator = validationInfo.validator;
                           var rules = validator.validationRules[validationInfo.ruleSetName];
                           for (var i = 0; i < rules.length; i++) {
                               watchRuleChange(validationInfo, rules[i]);
                           }
                       }
                   };


                   //alert(errorElementId);

                   // get element for which we are showing error information by id
                   var errorElement = $("#" + errorElementId);

                   console.log(angular.element(errorElement));

                   var errorElementController = angular.element(errorElement).controller('ngModel');
                   var validatorsController = angular.element(errorElement).controller('validator');

                   console.log(errorElementController);
                   console.log(validatorsController);

                   var getValidationInfo = function () {
                       return validatorsController && validatorsController.validationInfoIsDefined() ? validatorsController.validationInfo : null;
                   };

                   var validationChanged = false;
                   var subscribeToValidationChanged = function () {
                       if (validatorsController.validationInfoIsDefined()) {
                           validatorsController.validationInfo.validator.watchValidationChanged(function () {
                               validationChanged = true;
                               showErrorInfoIfNeeded();
                           });

                           // setup a watch on rule errors if it's not already set
                           watchCustomErrors(validatorsController.validationInfo);
                       }
                   };

                   var getErrorMessage = function (value) {
                       var validationInfo = getValidationInfo();
                       if (!validationInfo) {
                           return '';
                       }

                       var errorMessage = "";
                       var errors = validationInfo.validator.errors[validationInfo.ruleSetName];
                       var rules = validationInfo.validator.validationRules[validationInfo.ruleSetName];

                       for (var errorCode in errors) {
                           if (errors[errorCode]) {
                               var errorCodeRule = _.findWhere(rules, { errorCode: errorCode });
                               if (errorCodeRule) {
                                   errorMessage += errorCodeRule.validate(value).errorMessage;
                                   break;
                               }
                           }
                       }

                       return errorMessage;
                   };

                   var showErrorInfoIfNeeded = function () {
                       var validationInfo = getValidationInfo();
                       if (!validationInfo) {
                           return;
                       }

                       var needsAttention = validatorsController.ruleSetHasErrors() && (errorElementController && errorElementController.$dirty || validationChanged);
                       if (needsAttention) {
                           // compose and show error message
                           var errorMessage = getErrorMessage(element.val());

                           // set and show error message
                           element.text(errorMessage);
                           element.show();
                       } else {
                           element.hide();
                       }
                   };

                   subscribeToValidationChanged();
                   if (errorElementController)
                   {
                     scope.$watch(function () { return errorElementController.$dirty; }, showErrorInfoIfNeeded);
                   }
                   scope.$watch(function () { return validatorsController.validationInfoIsDefined(); }, subscribeToValidationChanged());
               }
           };
       }]);})
   (angular, $);

The error on the console is

  TypeError: Cannot read property 'validationInfoIsDefined' of undefined
at subscribeToValidationChanged (http://localhost/trax/app/Directives/validationMessage.js:50:52)
at link (http://localhost/trax/app/Directives/validationMessage.js:103:24)
at nodeLinkFn (https://code.angularjs.org/1.2.13/angular.js:6271:13)
at compositeLinkFn (https://code.angularjs.org/1.2.13/angular.js:5682:15)
at publicLinkFn (https://code.angularjs.org/1.2.13/angular.js:5587:30)
at boundTranscludeFn (https://code.angularjs.org/1.2.13/angular.js:5701:21)
at Object.controllersBoundTransclude [as transclude] (https://code.angularjs.org/1.2.13/angular.js:6292:18)
at https://code.angularjs.org/1.2.13/angular.js:20073:32
at Array.forEach (native)
at forEach (https://code.angularjs.org/1.2.13/angular.js:304:11) <span ng-switch-when="text" validation-message-for="{{field.label}}" class="ng-scope"> 
TommyK
  • 416
  • 2
  • 6
  • 24

1 Answers1

0

you are writing Directive name as camel case when you are define. in this case angular read this directive as - based values

so validation-Message-For should be validation-message-for in your Html code

<span ng-switch-when="text" validation-message-for="{{field.label}}"></span>

and change the input id attribute value assigning type:

remove the {{}} from id attribute

<input ng-switch-when="text" type="text" id="field.label" ng-model="field.data" validator="viewModel.validator"  ruleSetName="personFirstNameRules"/>

update

problem with ng-switch when. in your Plunker the input tags are not rendering as input field.

    Be aware that the attribute values to match against cannot be expressions. 
They are interpreted as literal string values to match against. For example,
 ng-switch-when="someVal" will match against the string "someVal" not against the 
value of the expression $scope.someVal.

refer this Question. StackOverflow Question

Updated Plunker

Community
  • 1
  • 1
chandu
  • 2,276
  • 3
  • 20
  • 35
  • The attrribute passes correctly into the directive. I can read field.label with a console output. The issue seems to be with the setting of the id on the input text field. The angular.element(errorElement).controller('ngModel'); shows undefined. If I hardcode the value of ID on the input text box everything is fine. – TommyK Jun 14 '14 at 12:27
  • remove the {{}} brackets from id value. so it should be – chandu Jun 14 '14 at 12:30
  • That didnt make a difference. hardcoding the value works. It seems the issue is with the assignment of field.label. – TommyK Jun 14 '14 at 12:48
  • Here it is in Plunker http://plnkr.co/edit/6hPxoJ The text boxes are not showing up here for some reason. – TommyK Jun 14 '14 at 13:11
  • the broblem with ng-switch-when. remove that one from you code – chandu Jun 14 '14 at 13:37
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/55624/discussion-between-tommyk-and-chandu). – TommyK Jun 14 '14 at 13:43