1

In my current project I need to create a dynamic form using AngularJS. I am already building the form following the ideas from this video here.

I can't seem to get the submitted data back to my controller. I only receive undefined in the console log.

Currently the data for the form is resolved in ui-router before the state is loaded, then copied to the controller's data property.

Unlike the video our form requires that questions are broken down into sections.

There is a ng-repeat over each section in the data, then a nested ng-repeat goes over each question. The type is determined and the proper directive for the question/field type is loaded to via ng-switch.

I whipped up a small Plunker to help illustrate as well. https://plnkr.co/edit/6dCnHiFDEYu03kfX07mr

Finally there are some types I am unsure how to handle, such as address or phone number which will be considered one question type but have multiple fields.

(e.g. [Street] [City] [State] [Zip])

Controller

namespace portal.dashboard.form{
class formCtrl{
    formData: portal.domain.interfaces.IHousingRequest;

    static $inject = ["formResolve"];
    constructor(private formResolve:any) {

        this.formData= this.loadHousingRequestFormData;
    }

    public submit(isValid,data) {
        if (isValid) {
            console.log(data);
        }
    }
}
angular
    .module("portal")
    .controller("formCtrl", formCtrl);
}

Directive for input type text

namespace portal.directives {
function inputText(): ng.IDirective {
    return {
        scope: {
            model: '='
        },
        controller: function ($scope: ng.IScope) {
            var directiveScope = $scope.$parent.$parent;
        },
        controllerAs:'vm',
        templateUrl: 'form/templates/input-text.html'            
    }
}

angular
    .module("portal")
    .directive("inputText", inputText);
}

input type html

<input type="text"
       ng-model="model"/>

HTML

    <form name="form" ng-submit="vm.submit(form.$valid, data)" novalidate>

    <!-- Section repeat -->
    <div ng-repeat="section in vm.formData.sections track by $index">
        <section>
            <div>
                <h4>
                    {{section.name}}<br />
                    <small ng-show="section.description">{{section.description}}</small>
                </h4>
            </div>
            <section>

                <!-- Section questions repeat -->
                <div ng-form="formFields" ng-repeat="field in section.fields track by $index">
                    <label>
                        {{field.name}}<br />
                        <small>{{field.description}}</small>
                    </label>

                    <!-- input field switch -->
                    <div ng-switch="field.type">
                        <div ng-switch-when="Text">
                            <input-text model="data.answer[$index]">
                            </input-text>
                        </div>
                        <div ng-switch-when="Email">
                            <input-email model="data.answer[$index]">
                            </input-email>
                        </div>
                    </div>
                </div>

            </section>
        </section>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</form>

1 Answer 1

1

You have to init $scope.data = {}; before using it, also use correct sectionIndex and fieldIndex to populate the answer:

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

app.controller('MainCtrl', function($scope) {
  $scope.data = {};
  $scope.sections = [{
    name: 'User Info',
    description: 'I\'m a description.',
    fields: [{
      label: "Name",
      type: "text"
    }, {
      label: "Email",
      type: "email"
    }]
  }, {
    name: 'Pet Info',
    description: '',
    fields: [{
      label: "Pet Breed",
      type: "text"
    }]
  }];

  $scope.submit = function(isValid, data) {
    console.log('submit fired');
    if (isValid) {
      console.log(data);
    }
  }
});


app.directive('inputText', function() {
  return {
    scope: {
      model: '='
    },
    controller: function($scope) {
      var directiveScope = $scope.$parent.$parent;
    },
    controllerAs: 'vm',
    template: '<input type="text" ng-model="model"/>'
  }

});

app.directive('inputEmail', function() {
  return {
    scope: {
      model: '='
    },
    controller: function($scope) {
      var directiveScope = $scope.$parent.$parent;
    },
    controllerAs: 'vm',
    template: '<input type="email" ng-model="model"/>'
  }

});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>

<body ng-app="plunker" ng-controller="MainCtrl">
    <form name="form" ng-submit="submit(form.$valid, data)" novalidate>

    <!-- Section repeat -->
    <div ng-repeat="(sectionIndex, section) in sections track by $index">
        <section>
            <div>
                <h4>
                    {{section.name}}<br />
                    <small ng-show="section.description">{{section.description}}</small>
                </h4>
            </div>
            <section>

                <!-- Section questions repeat -->
                <div ng-form="formFields" ng-repeat="(fieldIndex, field) in section.fields track by $index">
                    <label>
                        {{field.label}}<br />
                    </label>

                    <!-- input field switch -->
                    <div ng-switch="field.type">
                        <div ng-switch-when="text">
                            <input-text model="data.answer[sectionIndex][fieldIndex]">
                            </input-text>
                        </div>
                        <div ng-switch-when="email">
                            <input-email model="data.answer[sectionIndex][fieldIndex]">
                            </input-email>
                        </div>
                    </div>
                </div>

            </section>
        </section>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</form>
  </body>

Also I'm not sure why do you need this var directiveScope = $scope.$parent.$parent; in your directive's controller, do you really need this?

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

2 Comments

You're right that isn't needed, the video I linked to also linked to a github page. As I was referencing that I just put it in thinking it did something but looking back at it I see I don't need it for the way I'm intending to build the form.
@gboh glad it helped 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.