2

After 3 days of scouring stackoverflow and other sites, I have found myself back at square one.

My task: I need to validate dynamically generated form fields.

The HTML:

 <form name="myForm">
    <form-field content="field" model="output[field.uniqueId]" ng-repeat="field in formFields"></form-field>
 </form>

The controller:

var myApp = angular.module('myApp',[]);

function MyCtrl($scope) {
$scope.formFields = [
    {
    "fieldName": "Your Name",
    "uniqueId": "your_name_0",
    "fieldType": "text",
    "isMandatory": true
    },
    {
    "fieldName": "Description",
    "uniqueId": "description_1",
    "fieldType": "textarea",
    "isMandatory": true,
    }
];

$scope.output={};
}

The directive:

myApp.directive("formField",function($compile){
var templates = {
    textTemplate:'<div class="form-group"><label for="{{content.uniqueId}}" >{{content.fieldName}}</label> <span ng-show="content.isMandatory" class="sub_reqText">*</span><span ng-show="form.content.fieldName.$invalid">Please check this field.</span><input type="text" ng-model="model" name="{{content.uniqueId}}" class="form-control" ng-required="content.isMandatory" id="{{content.uniqueId}}"/> </div><br>',
    textareaTemplate:'<div class="form-group"><label for="{{content.uniqueId}}" >{{content.fieldName}}</label> <span ng-show="content.isMandatory" class="sub_reqText">*</span> <span ng-show="form.content.fieldName.$invalid">Please check this field.</span> <textarea ng-model="model" name="{{content.uniqueId}}" id="{{content.uniqueId}}"  class="form-control" ng-required="content.isMandatory"></textarea> </div>' 
};

var getTemplate = function(content, attrs){
    var template = {};
    template = templates[content.fieldType+"Template"];
    if(typeof template != 'undefined' && template != null) {
            return template;
        }
        else {
            return '';
        }
};


var linker = function(scope, element, attrs){        
    element.html(getTemplate(scope.content, attrs)).show();        
    $compile(element.contents())(scope);
}

return {
    restrict:"E",        
    replace:true,        
    link:linker,
    scope:{
        content:'=',
        model:'=?'
    }
};
});

There is clearly some scope issue because I cannot access the form fields outside of the directive and I cannot access the form name inside the directive. I also know $scope.myForm.name property cannot be an angular binding expression but I am not sure how to rewrite it so that it works.

This is the jsfiddle: http://jsfiddle.net/scheedalla/57tt04ch/

Any guidance will be very useful, thank you!

2
  • there are two scopes get created one because of ng-repeat and other because of isolated scope Commented Jan 23, 2015 at 22:45
  • Learned lots of concepts while solving this issue. BTW, it was Good question..Thanks. Commented Jan 26, 2015 at 9:00

1 Answer 1

2

While debugging the problem I found that, the name attribute is not properly compiled for form. It was showing {{content.uniqueId}} in name but actually it rendered properly on UI.

Eg. For below html.

<input type="text" ng-model="model" name="{{content.uniqueId}}" class="form-control" 
ng-required="content.isMandatory" id="{{content.uniqueId}}"/>

name rendered as name="your_name_0" but in form collection it was showing {{content.uniqueId}} with the interpolation directive.

Seems like name is not interpoluted properly.

Then found issue with AngularJS, "You can't set name attribute dynamically for form validation."

Note: Above mentioned issue has been fixed in Angular 1.3.(name attributes interpolates properly)

& If you wanted to work them inside ng-repeat, then you should always use nested ng-form. Members inside ng-repeat will have their own form, and using that inner form you can handle your validation. Link For Reference

CODE CHANGE

var templates = {
        textTemplate: '<ng-form name="form">'+
    '<div class="form-group">'+
        '<label for="{{content.uniqueId}}">{{content.fieldName}}</label> '+
          '<span ng-show="content.isMandatory" class="sub_reqText">*</span>'+
          '<span ng-show="form.input.$invalid">'+
          'Please check this field.'+
          '</span>'+
        '<input type="text" ng-model="model1" name="input" class="form-control" ng-required="content.isMandatory" id="{{content.uniqueId}}" /> '+
    '</div>'+
'</ng-form>'+
'<br>',
        textareaTemplate: '<ng-form name="form">'+
    '<div class="form-group">'+
        '<label for="{{content.uniqueId}}">{{content.fieldName}}</label>'+
          '<span ng-show="content.isMandatory" class="sub_reqText">*</span> '+
          '<span ng-show="form.textarea.$invalid">Please check this field.</span>'+
          '<textarea ng-model="model" name="textarea" id="{{content.uniqueId}}" class="form-control" ng-required="content.isMandatory"></textarea>'+
    '</div>'+
'</ng-form>'
    };

Only i changed the template html, basically added <ng-form></ng-form> for templates and handled the validation on basis it in inner form.

Here is your Working Fiddle

Hope this have cleared your understanding. Thanks.

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

2 Comments

Brilliant! This is exactly what I was looking for. Thank you so much! Glad you were able to learn a lot too :)
@user3495469 Glad to help you..Actually it was nice question. Did lots of R&D to find solution for you :)

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.