How to use a FormArray in a FormGroup in Angular 10

1.6k views Asked by At

I'm creating a form which contains normal inputs and one array of ingredients.

User while is filling the form must be able to add ingredient automatically.

It's first time when i'm creating form with FormArray and i've stucked.

On the console:

Screen

Here is what i've tried:

 export class RecipeAddComponent implements OnInit {
      recipe: IRecipe;
    
      recipeForm: FormGroup;
      ingredients: FormArray;
      
      ingredientForm: FormGroup;
      validationErrors: string[] = [];
    
      constructor(private recipeService: RecipeService, private fb: FormBuilder, private router: Router) {
    
         }
    
      ngOnInit(): void {
        this.intitializeRecipeForm();
      }
    
      intitializeRecipeForm() {
        this.recipeForm = this.fb.group({
          name: ['', Validators.required],
          preparationTime: ['', Validators.required],
          description: ['', Validators.required],
          ingredients: this.fb.array([this.createIngredient()])
        });
      }
    
    
      createIngredient(): FormGroup {
        return this.fb.group({
          name: '',
          amount: ''
        });
      }

  addRecipe() {
    this.recipeService.addNewRecipe(this.recipeForm.value).subscribe(response => {
      this.router.navigateByUrl('/recipes');
    }, error => {
      this.validationErrors = error;
    })
  }
    
      addIngredient(): void {
        this.ingredients = this.recipeForm.get('ingredients') as FormArray;
        this.ingredients.push(this.createIngredient());
      }
      }

HTML

<div class="container">
    <form class="p-5 col-md-5 col-sm-8 formShadow" [formGroup]='recipeForm' (ngSubmit)="recipeForm.valid && addRecipe()"
        autocomplete="off">
        <p class="h4 mb-4">Add new recipe</p>
        <app-text-input [formControl]='recipeForm.controls["name"]' [label]='"Name"'></app-text-input>

        <app-text-input [formControl]='recipeForm.controls["preparationTime"]' [label]='"Preparation Time"'
            [type]='"number"'>
        </app-text-input>

        <app-text-input [formControl]='recipeForm.controls["description"]' [label]='"Description"'></app-text-input>

        <div class="form-group">
            <ng-container formArrayName="ingredients">
                <div *ngFor="let ingredient of ingredients.controls; index as i">
                  <ng-container [formGroupName]="i">
                    <input formControlName="name" class="form-control" />
                    <input formControlName="amount"  class="form-control" />
                  </ng-container>
                </div>
              </ng-container>
        </div>
        <div class="row mt-5" *ngIf="validationErrors.length > 0">
            <ul class="text-danger">
                <li *ngFor="let error of validationErrors">
                    {{error}}
                </li>
            </ul>
        </div>

        <div class="form-group text-center">
            <button [disabled]="!recipeForm.valid" class="btn btn-outline-dark mr-2" type="submit">Register</button>
            <button class="btn outline-light mr-2" (click)="cancel()">Cancel</button>
        </div>
    </form>
</div>

Any hints would be helpful. It's first time when i'm doing this.

1

There are 1 answers

0
jagjeet On BEST ANSWER

This case seems like you have a parent category, and there can be multiple subcategories which may called as sub-categories form array. Any number of sub-categories will be there as per user requirements. So a formgroup and formarray can be designed as below :-

constructor(
    private formBuilder: FormBuilder
) { }

this.categoryForm = this.formBuilder.group({
   name: [undefined, [Validators.required]],
   image: [undefined, [Validators.required]],
   subCategories: this.formBuilder.array([

   ]),
});

To add new subcategory on demand, you can do as

addNewFieldSubCat() {
    (<FormArray>this.categoryForm.get("subCategories")).push(this.formBuilder.group({
      name: [undefined, [Validators.required]],
      image: [undefined, []],
   }));
}

To remove an existing row of sub-category, what you can do is:-

public removeSubCategory(index) {
   (<FormArray>this.categoryForm.get("subCategories")).removeAt(index);
}