creating an interactive form in angularjs with a variety of field options

I am currently working on a project that involves creating a dynamic form using AngularJS. I have been referring to a helpful video for guidance here.

However, I have encountered an issue where the submitted data is returning as undefined in my controller.

The form data is being resolved in ui-router before the state is loaded and then copied to the controller's data property.

In contrast to the video, our form requires questions to be organized into sections.

We use ng-repeat to iterate over each section in the data, followed by a nested ng-repeat to loop through each question. The directive for the question/field type is loaded via ng-switch based on the type of question.

To better illustrate this, I have created a small Plunker example: https://plnkr.co/edit/6dCnHiFDEYu03kfX07mr

One challenge I have faced is how to handle certain types like address or phone number, which are considered one question type but consist of multiple fields.

For example: [Street] [City] [State] [Zip]

Here is the structure of the 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);
}

And the 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);
}

HTML snippet for input type text:

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

Here is a snippet of the HTML code:

    <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>

Answer №1

Make sure to initialize $scope.data = {}; before using it, and ensure that you are using the 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>

Additionally, consider whether you truly need this

var directiveScope = $scope.$parent.$parent;
in your directive's controller. Do you have a specific reason for including it?

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Stop users from inputting particular words into a <textarea> box

I recently watched a tutorial on YouTube by the developphp guy and learned how to prevent people from inputting inappropriate words in my form's text area. However, I want to block multiple words instead of just one, but the tutorial didn't cove ...

Ways to troubleshoot an issue that arises when the `onChange` event is not utilized in a radio button component on a

When using this component for radio buttons without the Onchange function, I sometimes encounter the following error on the page related to onUpdate: TypeError: this.props.onUpdate is not a function onChange(e) { let value = e.target.value; this ...

Struggling to pass an array as a return value from a nested function

I'm seeking assistance with the code snippet below. I am encountering difficulties in accessing the "result" variable outside of the selectCb function scope. While "result" is properly assigned and functional within the selectCb scope, it becomes inac ...

Retrieving a column from a table and converting it into an array for utilization in a context processor on

I need to extract column data from a DB table using a Django context processor. This specific table column contains various versions of the primary data, so I want to gather all versions and pass them as context to an HTML page. The existing context proces ...

maximizing the benefits of async/await for improved productivity

While it's not recommended to use await in loops, I'm facing a unique challenge that I can't seem to efficiently solve. My goal is to achieve a final output for the variable values structured like this: { jobId1: [[..], [..], [..], [..]], ...

Creating an onchange event in CodeIgniter for dynamically generated select boxes within a view script

As a beginner with codeigniter, I am seeking some assistance. Within my controller, I retrieve data for both options and suboptions, then load the respective view using the code below. The view essentially generates a table consisting of select boxes passe ...

Error: The code could not be parsed - 'import' and 'export' can only be used with 'sourceType: module' (1:0)

I am facing an error related to Babel in my JavaScript app. I don't have much experience with Babel, and despite trying various solutions, I haven't been able to resolve it. The specific error occurs when I include "./src/index.js" in t ...

Navigating Protractor's Configuration File: Setting Up Error Messages

After working extensively with protractor, I've encountered an issue where a thrown error for timeout is displayed if an element is not found within 60 seconds. This default error message doesn't provide much insight into the actual problem. I&ap ...

Using Javascript to eliminate divs on a page that have the attribute display:none

Looking for a way to remove generated divs with display: none using JavaScript? Let's find a solution. <div id="workarea"> <div id="message" class="messages" style="display: none;">Your message was saved</div> <div id="message" c ...

Is using debounce with $scope.$apply a logical choice?

In my experience, I have come across a method that claims to decrease the number of $digest loops by incorporating debouncing into the $scope.$apply process. It looks something like this: $scope.$apply = _.debounce($scope.$apply, 250); Is this approach v ...

What could be causing the undefined properties of my input variables in Angular?

Currently, I am fetching data from a service within the app component and passing it down to a child component using @Input. Oddly enough, when I log the data in ngOnInit, it appears correctly in the child component. However, when I try to assign it to a v ...

Incorporate a personalized JavaScript code segment during the Vue build process

I am currently working with Vue CLI and I need to include a custom javascript section in the default template when I release my project. However, I do not want this section to be included during the debugging phase. For example, I would like to add the fo ...

angular2 angular-entity directive

I have developed a component that accepts a template: export class TemplateParamComponent implements OnInit { @Input() items: Array<any>; @Input() template: TemplateRef<any>; } Here is the HTML code: <template #defaultTemplate le ...

What are the circumstances under which JavaScript GCP libraries return null values?

My current project involves working with GCP and Firebase using typescript. I have been utilizing the provided libraries, specifically version 8 of Firebase, and have encountered some unexpected behavior. For instance (firebase, ver. 8.10.1) import 'f ...

Steps to incorporate an image overlay onto a clickable button

I'm currently working on enhancing the appearance of my T-Shirt color buttons by adding a heathered image overlay. While some shirts have plain colors, I want to show a pattern overlay on others. How can I include an image for specific buttons that ar ...

What is the best way to inform Netbeans that a specific portion of code should be recognized as JavaScript?

When working with the Zend Framework, I've been using the javascript helpers in the following form: <?php $this->headScript()->captureStart(); ?> //JavaScript code goes here <?php $this->headScript()->captureEnd(); ?> //Conti ...

JavaScript failing to adjust span width as intended

In an attempt to adjust the width of a span dynamically based on its content, I am facing a challenge. My application consists of multiple spans in rows and users can modify the content of these spans. To ensure uniformity in span width after content chang ...

Get rid of the upgrade button feature from TinyMCE editor

Recently, I started using tinymce in inline mode and it's a new tool for me. I have managed to adjust the text field input to my liking with just a few editing buttons. However, I am stuck trying to figure out how to get rid of the "Upgrade" button fr ...

The concept of nested labels: defining conditions for displaying specific sections of a label

Let's say I have a label that contains the following text: <label>This is a text. This is another text.</label> Is there a way to indicate that the second sentence should only be visible when a boolean value is true? For example: <la ...

How can I show a limited number of columns in a mat-table in Angular 6 depending on a specific condition?

Currently, I am facing an issue with my mat table as it contains several columns. In a specific scenario, I need to hide two of these columns. Typically, for a regular table, we would use a simple ngIf condition to achieve this. However, in the case of thi ...