Home > Mobile >  How to target form control nested in array, nested in object nested in array Angular Forms
How to target form control nested in array, nested in object nested in array Angular Forms

Time:10-31

I am fairly new to Angular and am trying to build a fairly complex form for a food delivery system I have been building.

I am currently building a form which would enable me to add a menu item to a restaurants menu.

I have built an angular form to do this, part of the form includes a section for addons, this would relate to things like sauces, flavors etc. The data is structured in such a way that there is an addons array that contains addon objects containing and addon type as well as an array of options relating to that type.

I have built a method to create a new addon in my addons array with two inputs, one for the name being a standard control taking a string and the other being an array nested in this object that includes all the addon options relating to that type.

I am able to add a new addon as well as addon options within that addon object but when trying to update values of those nested options I am unable to attach a formControlName to each of thos options which I need in order to update their values.

I keep getting the below error for reference

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

when creating the new option I'm not sure how to give it a unique formcontrol name so that its value can be updated. Any input would be massively appreciated.

Below is my code

TS.

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([]),
  });

Methods for adding new addon and adding a new addon 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" >
            <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" >
                <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>

CodePudding user response:

Your structure of FormGroup from the root form to option control should be:

Root FormGroup

--> addons FormArray

--> index of addon FormGroup

--> addonoptions FormArray

--> index of addonoption FormGroup

--> option FormControl


  1. Miss out formArrayName="addonoptions" for the template.

  2. Modify the way to iterate the addonoptions FormArray from addon FormGroup.

<ng-container formArrayName="addonoptions">
  <ng-container
    *ngFor="
      let addonoption of addonoptions(x).controls;
      let k = index
    "
  >
    <div [formGroupName]="k" >
      <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;
}

Demo @ StackBlitz

  • Related