1

In my angular app trying to add a dynamic form group with two form controls in the form array, how can I be able to add form controls dynamically in here? I have tried to add like this way [formControlName]="i" but getting this Cannot find control with path: 'dinings -> 0 -> 0'.

If I add statically formControlName="name" and formControlName="cuisine" not getting the error but values in formcontrols are not updating after addition.

This is what I have done -

HTML

 <div>
     <form [formGroup]="diningForm" (ngSubmit)="addDiningDetails()">
       ....
       <div class="added-dining-list">
         <ul>
           <li formArrayName="dinings" *ngFor="let dining of dinings;let i = index">
            <div [formGroupName]="i">
              <input type="text" class="form-input" placeholder="Dining Name" [formControlName]="i" />
              <input type="text" class="form-input" placeholder="Dining Cuisine" [formControlName]="i" />
              <a href="#">Delete</a>
           </div>
        </li>
        <li>
           <form [formGroup]="diningInfoForm" class="dining-info-form">
              <input type="text" class="form-input" formControlName="diningName"/>
              <input type="text" class="form-input" formControlName="diningCuisine"/>
              <a href="#" (click)="addDining($event)">Add Dining</a>
           </form>
        </li>
      </ul>
    </div>
  </form>

TS

ngOnInit(){
  //Dining Form
    this.diningForm = this._formBuilder.group({
        isOfferingDining: new FormControl('', [Validators.required]),
        dinings: this._formBuilder.array([]),
        diningInfo: new FormControl('')
    });

  //Dining info add form
    this.diningInfoForm = this._formBuilder.group({
        diningName: new FormControl('', [Validators.required]),
        diningCuisine: new FormControl('', [Validators.required])
    });
}

//Adding single dining in form array
addDiningMenu(event: MouseEvent) {
    event.preventDefault();
    if (this.diningInfoForm.invalid) {
        this.showErrorMessages();
    }
    const formValue = this.diningInfoForm.value;
    const formGroup = this._formBuilder.group({
        name: new FormControl(formValue.diningName, [Validators.required]),
        cuisine: new FormControl(formValue.diningCuisine, [Validators.required])
    });
    this.dinings.push(formGroup);
}

//Final Submit of the form
addDiningDetails() {
    this._messageService.clear();
    if (this.diningForm.invalid) {
        this.showErrorMessages();
        return;
    }
    console.log(this.diningForm.value);
}

//Getting form array
get dinings() {
    return (this.diningForm.get('dinings') as FormArray).controls;
}
Rahul Kundu
  • 95
  • 3
  • 13

4 Answers4

2

First things First, Can you nest forms? NO See Can you nest html forms?. Remove the nested form from your form

Next step is to have a picture of how you expect your object to be, We will produce a form that looks like below

{
   isOfferingDining: '',
   dinings: [
     {
        diningName: '',
        diningCuisine: ''
      },
      {
        diningName: '',
        diningCuisine: ''
      }
   ]
}

I am assuming that you have several dinings and each dining has a diningName and diningCuisine. Your form didn't do much in clarifying this

Change the getter dinings to return a FormArray

  //Getting form array
  get dinings() {
    return (this.diningForm.get('dinings') as FormArray);
  }

Now define the addDinings() and deleteDining() function

  addDining() {
    this.dinings.push(
      this._formBuilder.group({
        diningName: new FormControl('', [Validators.required]),
        diningCuisine: new FormControl('', [Validators.required])
      })
    );
  }
  deleteDining(i) {
    this.dinings.removeAt(i);
  }

Modify your html to match the form group

<form [formGroup]="diningForm" (ngSubmit)="addDiningDetails()">
  Is Offering Dining <input formControlName='isOfferingDining'>
  <div class="added-dining-list">
    <ul formArrayName="dinings">
      <li *ngFor="let dining of dinings.controls;let i = index" [formGroupName]="i">
        <input type="text" class="form-input" placeholder="Dining Name" formControlName="diningName" />
        <input type="text" class="form-input" placeholder="Dining Cuisine" formControlName="diningCuisine" />
        <a (click)="deleteDining(i)" href="#">Delete</a>
      </li>
    </ul>
    <a href="#" (click)="addDining()">Add Dining</a>
  </div>
  <button type="submit">Submit</button>
</form>

Now everything should work as expected

See Demo Here

Owen Kelvin
  • 14,054
  • 10
  • 41
  • 74
0

You need to specify the right form control name:

        <li formArrayName="dinings" *ngFor="let dining of dinings;let i = index">
            <div [formGroupName]="i">
              <input type="text" class="form-input" placeholder="Dining Name" [formControlName]="dining.name" />
              <input type="text" class="form-input" placeholder="Dining Cuisine" [formControlName]="dining.cuisine" />
              <a href="#">Delete</a>
           </div>
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
0

Try removing controls in get dinings().

//Getting form array
get dinings() {
    return this.diningForm.get('dinings') as FormArray;
}
N.F.
  • 3,844
  • 3
  • 22
  • 53
0

@Rahul you can change your dinnings return FormArray instead of controls.

In component.ts file

get dinings() {
  return this.diningForm.get('dinings') as FormArray;
}

In component.html file

<li formArrayName="dinings">
<div *ngFor="let dining of dinings().controls; let i = index">
  <div [formGroupName]="i">
    <input type="text" class="form-input" placeholder="Dining Name" formControlName="name" />
    <input type="text" class="form-input" placeholder="Dining Cuisine" formControlName="cuisine" />
    <a href="#">Delete</a>
  </div>
</div>
</li>

Ref: FormArray Reference Link

  • with this approach controls, are adding, whenever I am changing any values in the controls always getting the old and default ones(Initial values when controls was created) – Rahul Kundu Jun 09 '21 at 04:26
  • Please check this https://stackblitz.com/edit/angular-ivy-4gcwgl. If possible go through the reference link which was attached with the above answer. – Arunkumar Ramasamy Jun 09 '21 at 04:35