AngularJS dynamic Form does not get valid

90 views Asked by At

I have a dynamic Form in AngularJS, the input tags get replaced according to question type selected by the user. So the problem is, when user left a input tag blank which is required and switched to another type of questions, the form remains invalid(even the current form is valid).

I am adding the JsFiddle for it, you will get the idea.

HTML

<body ng-app="myApp" ng-controller="myCtrl">
<form name="myForm" novalidate>
    <div><input name='name' type='text' ng-model='name' ng-required='true' placeholder='name'></div>
    <div compile="myHtml"></div>
<input type="radio" ng-required='true' ng-click="addQuestion(1)" ng-model="radio" value="1"> Question 1 &amp; 3
<input type="radio" ng-required='true' ng-click="addQuestion(2)" ng-model="radio" value="2"> Question 2 &amp; 4
 <input type="submit" name="submit" ng-click="" ng-disabled="myForm.$invalid">   
</form>    
</body>

Javascript

// the main (app) module
var myApp = angular.module("myApp", []);

// add a controller
myApp.controller("myCtrl", function($scope) {
$scope.name = "John Doe";
$scope.myHtml = "";
$scope.radio="1";
$scope.question1 = 1;
$scope.question2 = 2;
$scope.question4 = 4;

$scope.addQuestion = function(id) {
    $scope.myHtml = "";
    if(id == 1) {
      $scope.myHtml += "<div><input name='question1' type='text' ng-model='question1' ng-required='true' placeholder='Question 1'></div>";
      $scope.myHtml += "<div><input name='question3' type='text' ng-model='question3' ng-required='true' placeholder='Question 3'></div>";
    };    
    if(id == 2) {
      $scope.myHtml += "<div><input name='question2' type='text' ng-model='question2' ng-required='true' placeholder='Question 2'></div>";  
      $scope.myHtml += "<div><input name='question4' type='text' ng-model='question4' ng-required='true' placeholder='Question 4'></div>";  
    };
};    
$scope.addQuestion(1);
});

// add a directive
myApp.directive('compile', ['$compile', function ($compile) {
return function(scope, element, attrs) {
    scope.$watch(
        function(scope) {
            // watch the 'compile' expression for changes
            return scope.$eval(attrs.compile);
        },
        function(value) {
            // when the 'compile' expression changes
            // assign it into the current DOM
            element.html(value);

            // compile the new DOM and link it to the current
            // scope.
            // NOTE: we only compile .childNodes so that
            // we don't get into infinite loop compiling ourselves
            $compile(element.contents())(scope);
        }
    );
};
}]);

Server JSON for question

$scope.fields = [{
    "caption": "Gender",
        "questionType": "RADIO",
        "optionValues": ["Male", "Female"],
        "fieldPriority": "REQUIRED"
}, {
    "caption": "City",
        "questionType": "TEXT",
        "optionValues": "",
        "fieldPriority": "REQUIRED"
}, {
    "caption": "Address",
        "questionType": "PARAGRAPH_TEXT",
        "optionValues": "",
        "fieldPriority": "REQUIRED"
}, {
    "caption": "Nationality",
        "questionType": "LIST",
        "optionValues": ["Indian", "American"],
        "fieldPriority": "REQUIRED"
}, {
    "caption": "Tea/Coffee",
        "questionType": "CHECKBOX",
        "optionValues": ["Tea", "Coffee"],
        "fieldPriority": "REQUIRED"
}];

Thanks

2

There are 2 answers

1
Ashot On

Do not store plane html in controller. Just use ng-if or ng-show to handle your logic.

4
Pankaj Parkar On

I'd refactor your code to use ng-include instead of compiling html from controller which is completely bad pattern in angularjs.

You could inject the template on basis of radio value ng-model

<body ng-app="myApp" ng-controller="myCtrl">
    <form name="myForm" novalidate>
        <div>
            <input name='name' type='text' ng-model='name' ng-required='true' placeholder='name'/>
        </div>
        <div ng-include="'question-set-'+radio +'.html'"></div>
        <input type="radio" ng-required='true' ng-click="addQuestion(1)" ng-model="radio" value="1" />Question 1 &amp; 3
        <input type="radio" ng-required='true' ng-click="addQuestion(2)" ng-model="radio" value="2" />Question 2 &amp; 4
        <input type="submit" name="submit" ng-click="" ng-disabled="myForm.$invalid">
    </form>
</body>
<script type="text/ng-template" id="question-set-1.html">
    <div> <input name = 'question1' type='text' ng-model = 'question1' ng-required = 'true' placeholder = 'Question 1' /> </div>
    <div><input name='question3' type='text' ng-model='question3' ng-required='true' placeholder='Question 3'/> </div>
</script>
<script type="text/ng-template" id="question-set-2.html">
    <div><input name ='question2' type ='text' ng-model='question2' ng-required = 'true' placeholder = 'Question 2' /> </div>
    <div><input name='question4' type='text' ng-model='question4' ng-required='true' placeholder='Question 4'/> </div>
</script>

Working Fiddle