Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nested formarray within group angular 6

Good Day.

I looked for the solution, and even though there are a view similar question to what I am asking, I am sure this one is a bit more unique and not a duplicate.

here is my html form:

<div class="form-group col-md-6" formGroupName="schema">
  <div formArrayName="currencies">
    <input type="text" class="form-control" id="percentage" formControlName="percentage" placeholder="Discount %*" required>
  </div>
</div>

and here is my ts formBuilder.

this.createPromo = this.fb.group({
      type: ['promotion'],
      name: ['', Validators.required],
      description: ['', Validators.required],
      enabled: ['', Validators.required],
      promotion_type: ['', Validators.required],
      start: ['', Validators.required],
      end: ['', Validators.required],
      schema: this.fb.group({
        currencies: this.fb.array([
          this.fb.group({
            percentage: '',
            currency: 'ZAR'
          })
        ])
      }),
    });

So I want my form to submit as a grouped array. However the error in the console is the following Cannot find control with path: 'schema -> currencies -> percentage', thus I am not able to submit my form as percentage is empty even after I input a number.

like image 231
Kruger Avatar asked Oct 16 '18 08:10

Kruger


People also ask

How do you bind FormArray in Angular 6?

Binding FormArray to Template Inside the div use ngFor to loop through each element of skills FormArray. let i=index will store the index value of the array in template local variable i . We will make use of it to remove the element from the skills array. Each element under the skills is a FormGroup .

Can FormArray contains FormGroup?

The FormArray is a way to Manage collection of Form controls in Angular. The controls can be FormGroup, FormControl, or another FormArray. Because it is implemented as Array, it makes it easier dynamically add controls.


1 Answers

You'll need the following for your scenario:

  1. A parent div with formGroupName="schema".
  2. Inside that, a div with formArrayName="currencies".
  3. Inside that, a div with ngFor="let currencyGroup of currencyFormGroups; let i = index;". Notice that currencyFormGroups is a getter in your Component Class.
  4. Inside that, a div with [formGroupName]="i" where i is the index that we created on the fly within *ngFor.
  5. Insde that, two inputs with formControlName="percentage" and formControlName="currency" respectively.

.

Here's all these steps translated to code:

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

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

  createPromo: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.createPromo = this.fb.group({
      'type': ['type'],
      name: ['name', Validators.required],
      description: ['description', Validators.required],
      enabled: ['enabled', Validators.required],
      promotion_type: ['promotion_type', Validators.required],
      start: ['start', Validators.required],
      end: ['end', Validators.required],
      schema: this.fb.group({
        currencies: this.fb.array([
          this.fb.group({
            percentage: 'percentage',
            currency: 'ZAR'
          }),
          this.fb.group({
            percentage: 'percentage',
            currency: 'INR'
          }),
        ])
      }),
    });
  }

  get currencyFormGroups() {
    return (<FormArray>(<FormGroup>this.createPromo.get('schema')).get('currencies')).controls;
  }

}

Template:

<form [formGroup]="createPromo">

  ...

  <div formGroupName="schema">
    <div formArrayName="currencies">
      <div *ngFor="let currencyGroup of currencyFormGroups; let i = index;">
        <div [formGroupName]="i">
          <input 
            type="text" 
            name="percentage"
            formControlName="percentage">
          <input 
            type="text" 
            name="currency"
            formControlName="currency">
        </div>
      </div>
    </div>
  </div>

</form>

Here's a Sample StackBlitz for your ref.

PS: For simplicity's sake, I've considered all the form controls as input. Please make your changes accordingly.

like image 79
SiddAjmera Avatar answered Oct 07 '22 03:10

SiddAjmera