Guide to accessing nested form controls within an array and object in Angular Reactive Forms

As a newcomer to Angular, I am in the process of creating a complex form for a food delivery application that I have been developing.

The form I am currently working on is designed to allow me to add a new menu item to a restaurant's menu.

In this Angular form, there is a section dedicated to addons such as sauces and flavors. The data structure includes an array named addons which contains objects representing different addon types along with arrays of options related to each type.

To create a new addon within the addons array, I have implemented a method that takes two inputs: one for the name (a standard string input) and another nested array containing all the addon options for that type.

While I am able to successfully add new addons and their options, I encounter an issue when trying to update the values of nested options. Specifically, I am unable to assign a formControlName to each option, which is necessary for updating their values. This results in the error message:

vendor.js:63956 ERROR Error: Cannot find control with path: 'addons -> 0 -> 0 -> option

I am unsure how to provide a unique formcontrol name to each newly created option to enable value updates. Any assistance on this matter would be greatly appreciated.

Below is the code snippet:

Main Form:

menuForm = this.builder.group({
  name: this.builder.control<string>('', Validators.required),
  price: this.builder.control<string>('', Validators.required),
  description: this.builder.control<string>('', Validators.required),
  itemType: this.builder.control<string>('', Validators.required),
  image: this.builder.control<NonNullable<any>>('', Validators.required),
  imageName: this.builder.control<string>('', Validators.required),
  categories: this.builder.array([]),
  relatedsides: this.builder.array([]),
  addons: this.builder.array([]),
});

Functions for adding a new addon and its option:

addAddon() {
  const addOnForm = this.builder.group({
    addonname: ['', Validators.required],
    addonoptions: this.builder.array([]),
  });
    
  this.addons.push(addOnForm);
}
    
addAddonOption(i: number) {
  const addOnOptionForm = this.builder.group({
    option: this.builder.control<string>(''),
  });
    
  this.addons.value[i].addonoptions.push(addOnOptionForm);
    
  console.log('addons with options', this.addons.value);
}

HTML:

<!-- Addons Array -->

      <ng-container type="form" formArrayName="addons">
        <h4>Add Addons</h4>
        <ng-container *ngFor="let addOnForm of addons.controls; let x = index">
          <div [formGroupName]="x" class="addons-form-row">
            <mat-form-field appearance="fill">
              <input matInput placeholder="Addon" formControlName="addonname" />
            </mat-form-field>

            <button type="button" (click)="deleteAddOn(x)">Delete Addon</button>
            <button type="button" (click)="addAddonOption(x)">
              add addon option
            </button>

            <ng-container
              *ngFor="
                let addonoption of addons.value[x].addonoptions;
                let k = index
              "
            >
              <div [formGroupName]="k" class="imbeded-addon-options">
                <mat-form-field appearance="fill">
                  <input
                    matInput
                    type="text"
                    placeholder="Add On Option"
                    formControlName="option"
                  />
                </mat-form-field>
              </div>
            </ng-container>
          </div>
        </ng-container>
      </ng-container>
      <div>
        <button type="button" (click)="addAddon()">Add Addon</button>
      </div>

Answer №1

Ensure your hierarchy of FormGroup starting from the main form to the option control follows this structure:

Main Form FormGroup

--> addons FormArray

--> index of addon FormGroup

--> addonoptions FormArray

--> index of addonoption FormGroup

--> option FormControl


  1. Make sure to exclude

    formArrayName="addonoptions"
    in the template.

  2. Adjust how you iterate over the addonoptions FormArray within the addon FormGroup.

<ng-container formArrayName="addonoptions">
  <ng-container
    *ngFor="
      let addonoption of addonoptions(x).controls;
      let k = index
    "
  >
    <div [formGroupName]="k" class="imbeded-addon-options">
      <mat-form-field appearance="fill">
        <input
          matInput
          type="text"
          placeholder="Add On Option"
          formControlName="option"
        />
      </mat-form-field>
    </div> 
  </ng-container>
</ng-container>
addAddonOption(i: number) {
  const addOnOptionForm = this.builder.group({
    option: this.builder.control<string>(''),
  });

  this.addonoptions(i).push(addOnOptionForm);

  console.log('addons with options', this.addons.value);
}

addonoptions(addonFormIndex: number): FormArray {
  return (this.addons.get(`${addonFormIndex}`) as FormGroup).controls
    .addonoptions as FormArray;
}

Check out the Demo on StackBlitz

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

Confirm button title by verifying part of the label that contains a space

I'm facing an issue with clicking a button using the following code: await page.getByRole('button', { name: '3 Employees' }).click(); The problem is that the button's name fluctuates based on the number of employees, causing ...

How to eliminate a particular validator from a form group in Angular

My goal is to eliminate the specific validator from the validator array so that I can reconfigure the controls when certain values have changed. I am aware of the traditional solution where I would need to repeatedly set validators. checked(event: MatC ...

Angular 4 - Issues with route configurations

My Angular application is running smoothly on localhost:4200 using ng serve. The node server can be found at localhost:3000. After running ng build, a bundle file is generated and properly served from localhost:3000 thanks to the line app.use(express.sta ...

Some variables are needed but not provided (please use: --variable APP_DOMAIN=value --variable PAGE_LINK_DOMAIN=value)

I'm trying to set up Firebase Dynamic Links. Following the documentation instructions, I encountered the following error. Any tips on how to determine the values for my app? APP_DOMAIN and PAGE_LINK_DOMAIN I want to generate dynamic links programmat ...

Angular 8 - Unraveling the Mystery Behind its Initial Page Discovery

I am facing an issue with my Angular 8 application where the login page is being displayed at startup. I have checked the routing module but couldn't find anything that explicitly sets this page as the startup page. Any suggestions on what might be c ...

Having trouble retrieving data from mobx store in Ionic3

I am attempting to retrieve a value from the @computed getCategories() function, but every time I try to call this function, I encounter the following error: Cannot invoke an expression whose type lacks a call signature. Type 'any[]' has no comp ...

Is there a way to send routerLink to an HTML element like <div [innerHTML]=""> without triggering the warning: "sanitizing HTML stripped some content"? Check out https://g.co/ng/security#xss for more information

Within the parent component, I am using the following construction: const link = `<a routerLink="${group.id}">${group.name}</a>`; // also tried using [routerLink] When attempting to work with it in a child component, I implement it l ...

When using RXJS, the method BehaviorSubject.next() does not automatically notify subscribers

In my project, I have a service set up like this: @Injectable({ providedIn: 'root' }) export class MyService { private mySubject = new BehaviorSubject({}); public currentData = this.mySubject.asObservable(); updateData(data: any) { ...

What could be causing my NodeJS Backend to not retrieve the data properly?

For a current project, I am tasked with building a mobile application using Flutter for the frontend and NodeJS for the backend. To facilitate this, I have acquired a VPS from OVHcloud running Ubuntu 20.04. Following various tutorials, I set up a server as ...

The PrimeNG table fails to refresh upon initial modification

I'm working with a prime-ng table of shops, where I have the ability to remove and add shops to a list. The scenario: Whenever a shop is added, the ChildComponent emits an event to the ParentComponent, which then adds the shop to the list and updates ...

Clipanion is unable to fulfill requests

I followed the official Clipanion documentation for creating a CLI tool () and even cloned an example from here - https://github.com/i5ting/clipanion-test, but I'm facing issues when trying to execute my commands. It seems like I might be struggling ...

Utilizing .js file alongside declaration files .d.ts in Angular: A guide

I am facing an issue with my Angular 7 app where I need to include some typed JS constants from outside of the project. These constants are essential for the AngularJS app and need to be kept in a separate js file. I have defined a new path in the tsconfig ...

transferring attributes from a higher component to a lower one (modal)

https://i.sstatic.net/tSXb5.png https://i.sstatic.net/H4xmj.png I am relatively new to React and I want to share a detailed problem description: I have a Todo project that consists of multiple interfaces. The main interface displays all the lists, each ...

Angular Binding issue - Unable to bind to 'ngModel' as it is not recognized as a valid property of 'input' element, despite the property being present

I have developed a component class like the one below and I am attempting to link the class fields to the template, but encountered the following error: ERROR in src/app/admin/projects/projects.component.html: 41:34 - error NG8002: Can't bind to &ap ...

The input field cannot accommodate the lengthy value in the Mat Select option

When a user selects a value in my mat select, it doesn't display well in the selection box. The text wraps when the selection is opened, but once a choice is made, it gets cut off without proper spacing between the ellipses and the dropdown arrow. Th ...

Tips for utilizing an adaptive design with Angular

I am working on designing a page that allows for scrolling if needed. On each section of the page, I will be incorporating specific components with unique colors to enhance the layout. However, my current HTML code is not producing the desired result as sh ...

Ways to mandate a field to only be of type object in TypeScript

I need to design a type that includes one mandatory property and allows for any additional properties. For instance, I require all objects to have an _id property of type string. {_id: "123"} // This will meet the criteria {a: 1} // This will not work as i ...

The modeless service in FeathersJS is failing to provide the correct JSON response

Could someone please explain to me how the service creation process works? I have been struggling for hours trying to receive JSON objects that do not meet my expectations. After much trial and error, I have come up with the following code for the before h ...

Utilizing TypeScript to Define Object Properties with String Keys and Values within Parentheses

I am in the process of developing a telegram bot I have the need to save all my messages as constants My message schema is structured as follows: type MessagesSchema = { [K in keyof typeof MessagesEnum]: string } Here is an example implementatio ...

Guidelines for transitioning an AngularJS module for injection into an Angular 2 component

After diving into the Angular 2 upgrade guide and successfully setting up a hybrid app (combining ng1 as a base code with components and services gradually transitioning to ng2), I've hit a snag. How do I incorporate 3rd party ng1 modules so that Angu ...