Hi i have a component template recipe-edit.component.html:
<div class="row">
<div class="col-xs-12">
<form [formGroup]="recipeForm" (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-xs-12">
<button type="submit" class="btn btn-success">Save</button>
<button type="button" class="btn btn-danger">Cancel</button>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label for="name">Name</label>
<input
type="text"
id="name"
class="form-control"
formControlName="name"
/>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label for="imagePath">Image URL</label>
<input
type="text"
id="imagePath"
class="form-control"
formControlName="imagePath"
/>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<img src="" class="img-responsive" />
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label for="description">Description</label>
<textarea
type="text"
id="description"
class="form-control"
rows="6"
formControlName="description"
></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12" formArrayName="ingredients">
<div
class="row"
*ngFor="let ingredientCtrl of controls; let i = index"
[formGroupName]="i"
>
<div class="col-xs-8">
<input
type="text"
class="form-control"
[formControlName]="name"
/>
</div>
<div class="col-xs-2">
<input
type="number"
class="form-control"
[formControlName]="amount"
/>
</div>
<div class="col-xs-2">
<button class="btn btn-danger">X</button>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
And the corresponding ts recipe-edit.component.ts is:
import { Component, OnInit } from '@angular/core';
import { FormArray, FormControl, FormGroup, NgForm } from '@angular/forms';
import { ActivatedRoute, Params } from '@angular/router';
import { RecipeService } from '../recipe.service';
@Component({
selector: 'app-recipe-edit',
templateUrl: './recipe-edit.component.html',
styleUrls: ['./recipe-edit.component.css'],
})
export class RecipeEditComponent implements OnInit {
recipeForm: FormGroup;
id: number;
editMode: boolean = false;
constructor(
private route: ActivatedRoute,
private recipeService: RecipeService
) {}
ngOnInit() {
this.route.params.subscribe((params: Params) => {
this.id = +params['id'];
this.editMode = params['id'] != null;
this.initForm();
});
}
private initForm() {
let recipeName = '';
let recipeImagePath = '';
let recipeDescription = '';
let recipeIngredients = new FormArray([]);
if (this.editMode) {
const recipe = this.recipeService.getRecipe(this.id);
recipeName = recipe.name;
recipeImagePath = recipe.imagePath;
recipeDescription = recipe.description;
if (recipe['ingredients']) {
for (let ingredient of recipe.ingredients) {
recipeIngredients.push(
new FormControl({
name: new FormControl(ingredient.name),
amount: new FormControl(ingredient.amount),
})
);
}
}
}
this.recipeForm = new FormGroup({
name: new FormControl(recipeName),
imagePath: new FormControl(recipeImagePath),
description: new FormControl(recipeDescription),
ingredients: recipeIngredients,
});
}
get controls() {
return (<FormArray>this.recipeForm.get('ingredients')).controls;
}
onSubmit() {
console.log(this.recipeForm);
}
}
But somehow in the console i get the following error when trying to reach the endpoint:
ERROR Error: Cannot find control with path: 'ingredients -> 0 -> '
multiple times… Can someone explain me what is happening here and why?
The problem is in the code that generates the array of formControls at the end of the template when using *ngFor angular directive
Thank you in advice!
I’ve tried to generate new array to extract only the value of the FormControl like this:
get controls() {
return (<FormArray>this.recipeForm.get('ingredients')).controls.map(
(control) => control.value
);
}
But it is not the solution and is bad code i don’t want this
2
Answers
I Found the problem...
starting with the mapping of controls in my template:
must be:
It's like that because I want to assign to the property formControlName a static value "name" which is a string and not the corresponding value of a property named name.
Then to add multiple controls to a FormControlArray you have to add a new FormGroup with nested FormControls so:
becomes:
Hope that can help you out
we should always have a formgroup contain the form controls for the form array, then please refer the below stackblitz on how the html is modified inorder to make the changes work.
html
ts
stackblitz