Encountering the error "TypeError: Unable to access property 'controls' of undefined" when utilizing formArray in Reactive forms

Hi there, I am currently working on creating a dynamic form using formArray in Angular. However, I have run into an issue with the error message "TypeError: Cannot read property 'controls' of undefined."


import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, FormArray } from '@angular/forms';

@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {
 title = 'Trainer Registration Form';
 registrationForm: FormGroup;

 get LanguagesForm() {
    return this.registrationForm.get('Languages') as FormArray;
 }

 addLanguage() {
  this.LanguagesForm.push(this.fb.control(''));
}

constructor(private fb: FormBuilder) {}

ngOnInit(){
 this.registrationForm = this.fb.group({
  personalDetails: this.fb.group({
    name: this.fb.group({
      firstName: [''],
      lastName: ['']
    }),
    aboutYours: [''],
    dob: [''],
    Languages: this.fb.array([]),
    wTT: ['']
  })
 });

}

onSubmit() {
 console.log(this.registrationForm.value);
 // this._registerationservice.register(this.registrationForm.value).subscribe(
 //   response => console.log('Success', response),
 //   error => console.log('Error',error)
 // );
}

}

Expected Result: When the user clicks on the button "Add Language," a new input field should be created.

Actual Result: I am receiving the error message "TypeError: Cannot read property 'controls' of undefined"

app.component.html File

<div style="text-align:center">
<h1>Welcome to {{ title }}!</h1>
</div>

<mat-horizontal-stepper >

  <mat-step [stepControl]="personalDetails">
    <ng-template matStepLabel>Enter Personal Details</ng-template>
    <div formGroupName="personalDetails">
      <div formGroupName="name">
          <div class="form-group">
            <label>First Name : </label>
            <input type="text" formControlName="firstName" class="form-control" >
          </div>

          <div class="form-group">
            <label>Last Name : </label>
            <input type="text" formControlName="lastName" class="form-control">
          </div>
      </div>    
      <div class="form-group">
          <label>DOB : </label>
          <input type="date" formControlName="dob" class="form-control">
        </div>

        <div class="form-group">
          <label>About Yourself : </label>
          <textarea formControlName="aboutYours" class="form-control"></textarea>
        </div>

        <div class="form-group">
            <label>Language(s) : </label>
            <button type="button" class="btn btn-secondary btn-sm m-2" (click)="addLanguage()">Add Language</button>
            
            <div formArrayName="Languages">
                <div *ngFor="let lang of langsform.controls; let i =index;">
                    <input type="text" class="form-control" [formControlName]="i">
                </div>
              </div>

          </div>


</mat-horizontal-stepper>
</form>
</div>

Answer №1

This issue occurred because the upper formGroup for personalDetails was not set. Therefore, it was unable to find the control named Languages within the personalDetails form group in the registrationForm. Additionally, there is a typo in LanguagesForm.controls, it should be replaced with 'Languages.controls'.

<div class="form-group">
  <label>Language(s) : </label>
  <button type="button" class="btn btn-secondary btn-sm m-2" (click)="addLanguage()">Add Language</button>

  <div [formGroup]="registrationForm"> <!-- 👈 -->
    <div [formGroupName]="'personalDetails'"> <!-- 👈 -->

      <div formArrayName="Languages">
        <div *ngFor="let lang of registrationForm.get('personalDetails').get('Languages').controls; let i =index;">
          <input type="text" class="form-control" [formControlName]="i">
        </div>

      </div>
    </div>
  </div>
</div>

To access the Languages Form, you can use the get property like this

  langsform() :FormArray { 
    return this.registrationForm.get('personalDetails').get('Languages') as FormArray 
  }

template

<div [formGroup]="registrationForm">
  <div [formGroupName]="'personalDetails'">

    <div formArrayName="Languages">
      <div *ngFor="let lang of langsform.controls; let i =index;">
          <input type="text" class="form-control" [formControlName]="i">
      </div>
    </div>
  </div>
</div>

Check out the demo here 🔥🔥

Answer №2

From my perspective, the issue arises from initializing the registrationForm object within onInit, as the template has already been parsed by this point. To address this, consider placing an *ngIf="this.registrationForm" directive on the

<div formArrayName="Languages">
.

Answer №3

Here is an alternative approach to solve your issue:

For the HTML part, implement the following code snippet:

<div class="form-group">
      <div formArrayName="languages">
        <label>Languages</label>

        <div class="row">
          <div class="col-8">
            <input type="text" class="form-control" id="languages">
          </div>
          <div class="col-4">
            <button type="button" class="btn btn-primary" (click)="onAddLanguages()">Add</button>
          </div>
        </div>

        <div class="form-group row" *ngFor="let languages of registrationForm.get('languages').controls; let i = index">
          <div class="col-8">
            <input type="text" class="form-control" [formControlName]="i">
          </div>
          <div class="col-4">
            <button type="button" class="btn btn-danger" (click)="onDeleteLanguages(i)">Delete</button>
          </div>
        </div>
      </div>
    </div>

And for the TypeScript part, use the following code snippets:

this.registrationForm = new FormGroup({
       'languages': new FormArray([])
});
onAddLanguages() {
const control = new FormControl(null, Validators.required);
(<FormArray>this.registrationForm.get('languages')).push(control)
}
onDeleteLanguages(index) {
(<FormArray>this.registrationForm.get('languages')).removeAt(index)
}

Answer №4

You have titled your FormArray as "Languages" rather than LanguagesForm.

<div *ngFor="let Languages of registrationForm.controls.personalDetails.controls.Languages.controls; let i =index;">
      <input type="text" class="form-control" [formControlName]="i">
</div>

Update: I have made changes to the getLangsform as well as the <mat-step> and <form> tags. https://stackblitz.com/edit/angular-lc8mu1

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

Every time I try to call the event in jQuery for the second time, it fails to work

I am currently working on a website that features an image gallery powered by the jquery wookmark plugin with filtering capabilities. Recently, I integrated the colorbox plugin (which was provided as an example by wookmark) to enhance the user experience. ...

What is the best way to call another "put" action method within the same controller file?

My project revolves around the interaction of two models - User and Request. A User can create a food delivery Request, attaching tokens as rewards. Another User can then help deliver the request and claim the tokens. Within the same controller.js file, I ...

When using Jquery, hovering over an element will cause the full title to be

I have created a toggle div that displays an ellipsis (...) when the long title is longer than 30 characters. Now, I want the full text of the long title to appear when hovering over the div. Check out this JS Fiddle for reference. JS $('#popu ...

Is it possible to delete a section of the URL within an anchor tag prior to the #anchor

My webpage contains a link that looks like this: <li class="jump"><a href="http://example.com/#about">About Me</a></li> I am interested in using jQuery to eliminate the 'http://example.com/' section of any URL found with ...

Transform JSON into a JavaScript array object using node.js

My knowledge of Javascript is limited and I need assistance with a .json file that has the following structure: { "results": [ { "challenger": { "__type": "Pointer", "className": "Player", "objectId": "STWAxAHKay" }, "c ...

Despite having both React and Firebase enabled, the "sign-in provider" feature appears to be disabled

Within my Authentication settings, the Sign-in Method is configured to use Email and Password as enabled. I've set up a handler for form submission that looks like this: createUser(e){ e.preventDefault(); const email = this.createEmail.value ...

Using Multithreading and the Subscribe/Publish Methodology in JavaScript

Is it true that JavaScript does not support multithreading? I am seeking expert advice on a specific scenario. I need to make an AJAX call and upon successful completion, trigger a set of events to update different parts of the UI simultaneously. Would ...

Getting request parameters within Model in Loopback can be done by accessing the `ctx`

common/models/event.json { "name": "Event", "mongodb": { "collection": "event" }, "base": "PersistedModel", "idInjection": true, "options": { "validateUpsert": true }, "http": { "path": "organizer/:organizer_id/events" }, "properties": {}, "va ...

There was an error with CreateListFromArrayLike as it was called on a non-object

I am receiving a list of over 1000 numbers from an API and storing it in a variable called "number". My goal is to find the highest number from this list. However, I encountered an error while attempting to do so: TypeError: CreateListFromArrayLike called ...

Avoid duplication of values in Angular4 when using *ngFor

Looking for assistance in updating an AngularJS project to Angular4. I have a JSON rest endpoint that returns a list of activities sorted by date and time. In AngularJS, I utilized ng-repeat to iterate through the data and ng-show to prevent duplicate entr ...

The information is being properly displayed in the console, but when attempting to show it on the webpage, an ERROR occurs with the message: "Error trying to differentiate '[object Object]'"

The data is successfully displayed in the console. However, when trying to display it on the page, an error occurs: ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed services getdetails(id:number) : ...

The model `user` does not have a primary key attribute specified. It is required for all models to have a primary key attribute defined

I have defined a waterline model below: var Waterline = require('Waterline'); var bcrypt = require('bcrypt'); var User = Waterline.Collection.extend({ identity: 'user', datastore: 'myMongo', autoPK: false, attribut ...

Updating a Zendesk ticket with multiple comments

I've been attempting to update a ticket on Zendesk using their API and adding multiple comments. However, it seems that I might be utilizing the incorrect format as the comments are not showing up on my Zendesk dashboard... The JSON format I'm c ...

Add a click event listener to the body element using a button click, without causing it to trigger

What is the current situation: A button is clicked by the user The menu opens (list items display = block) The function to close the menu is connected to the <body> The function to close the menu is immediately triggered, causing the menu to close ...

Attempting to have this .js lightbox appear as soon as the page loads

This Lightbox is absolutely stunning! However, I am looking for a way to automatically trigger the lightbox when the page loads. ...

Issue encountered when attempting to establish a new loadingController with LoadingOption

Hey there, I am relatively new to Ionic and I encountered an issue while trying to create a new loading screen. Argument of type '{ content: string; }' is not assignable to parameter of type 'LoadingOptions'. Object literal may only s ...

Issues with Angular radio buttons are causing them to not be selected properly

When it comes to radio buttons, they should be checked based on certain conditions. <input data-ng-checked="user.contract1 || user.contract2" data-ng-model="user.agreed" type="radio" data-ng-value="true"> Yes <input data-ng-checked="!user.contrac ...

The final output message from the NPM package is displayed right at the conclusion

Is there a way to add a log message at the end of the npm install process? To enable CLI tab autocompletion run: mypackage completion >> ~/.profile <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d5a5a7bab2a7b0a6 ...

Sending a value to a text box using json data transmission

I am having trouble accessing data from a js file and fetching the value to an html text box. Despite trying, I'm unable to get the desired result. Below are the contents of samle.js file and jsonhtml.html file: { "var1": "1", "var2": "2" } <scri ...

What would be the best way to create a JavaScript function that emulates the functionality of an Upgrade Button?

I am currently working on developing a clicker game and have reached the point where I need to implement a function for the 'upgrade click' button. This function should deduct a certain amount of money when clicked, while also increasing the amou ...