I tried to Add FormsArray in my Project while using ReactiveFormsModule but i am receiving the error and it is displayed as :-
Cannot find control with unspecified name attribute . and also can't we add FormsArray by using template driven form ?
Below is my code for this .
recipe-edit.component.ts
<div class="row">
<div class="col-xs-12">
<form [formGroup]="recipeform" (ngSubmit)="onsubmit()" #f="ngForm">
<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"
formControlName="name"
class="form-control">
</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"
formControlName="image"
class="form-control"
>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12" >
<img class="img-responsive">
</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"
formControlName="description"
rows="6"></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12" >
<div
class="row"
formArrayName="ingredients"
*ngFor="let ctrl of recipeform.get('ingredients').controls;let i=index"
[formGroupName]="i"
style="margin-top: 10px;">
<div class="col-xs-8">
<input
type="text"
formControlName="name"
class="form-control"
>
</div>
<div class="col-xs-2">
<input
type="number"
class="form-control"
formControlName="amount"
>
</div>
<div class="col-xs-2">
<button
type="button"
class="btn btn-danger"
>X</button>
</div>
</div>
<hr>
<div class="row">
<div class="col-xs-12">
<button
type="button"
class="btn btn-success"
>Add Ingredient</button>
</div>
</div>
</div>
</div>
</form>
recipe-edit.component.ts
import { Component, OnInit, ViewChild } from '@angular/core';
import {NgForm, FormGroup, FormControl, FormArray} from
'@angular/forms';
import { Recipeservice } from '../recipe.service';
import { ActivatedRoute, Router } from '@angular/router';
@Component({
selector: 'app-recipe-edit',
templateUrl: './recipe-edit.component.html',
styleUrls: ['./recipe-edit.component.css']
})
export class RecipeEditComponent implements OnInit {
@ViewChild('f') recipeform:FormGroup
id:number
editmode=false
constructor(private reservice:Recipeservice,private
route:ActivatedRoute,router:Router) { }
ngOnInit() {
this.route.params.subscribe(
(params)=>{
this.id=+params['id']
console.log(this.id)
this.initform()
}
)
}
onsubmit(){
console.log(this.recipeform)
}
private initform(){
let recipename=''
let recipeimage=''
let recipedescription=''
let recipeingredients=new FormArray([])
this.editmode=true
if(this.editmode){
const recipe=this.reservice.getrecipe(this.id)
recipename=recipe.name
recipeimage=recipe.imagepath
recipedescription=recipe.description
if(recipe.ingredients!=null){
for(let ingredient of recipe.ingredients){
recipeingredients.push(new FormGroup({
'name':new FormControl(ingredient.name),
'amount':new FormControl(ingredient.amount)
}))
}
}
}
this.recipeform=new FormGroup({
'name':new FormControl(recipename),
'image':new FormControl(recipeimage),
'description':new FormControl(recipedescription),
'ingredients':recipeingredients
})
}
}
It is highly recommended by the person who wrote Angular forms to not mix Template-driven and Reactive forms. FormArray is part of Reactive forms.
There are a few 'template-driven' form techniques in your code that you should consider removing, such as this:
@ViewChild('f') recipeform:FormGroup
You are defining the recipeform
FormGroup in your code, then generating a reference to it in your template, then passing that reference back to your code. (I'm surprised that this does not cause an error.)
I would recommend:
1) Removing #f="ngForm"
from your template. That is only needed for template-driven forms.
2) Replacing @ViewChild('f') recipeform:FormGroup
with just a declaration for recipeform: FormGroup
.
3) Using FormBuilder instead of instances of FormGroup and FormControl.
4) Is this an async call: const recipe=this.reservice.getrecipe(this.id)
, if so, you need to use subscribe
to get the data.
Here is an example of one of my reactive forms using FormBuilder and a FormArray:
export class CustomerComponent implements OnInit {
customerForm: FormGroup;
ngOnInit() {
this.customerForm = this.fb.group({
firstName: ['', [Validators.required, Validators.minLength(3)]],
lastName: ['', [Validators.required, Validators.maxLength(50)]],
addresses: this.fb.array([this.buildAddress()])
});
}
addAddress(): void {
this.addresses.push(this.buildAddress());
}
buildAddress(): FormGroup {
return this.fb.group({
addressType: 'home',
street1: ['', Validators.required],
street2: '',
city: '',
state: '',
zip: ''
});
}
}
You can find a complete working example here: https://github.com/DeborahK/Angular-ReactiveForms
I have a second example in the same repo that includes the parameter code similar to what you are doing:
ngOnInit(): void {
this.productForm = this.fb.group({
productName: ['', [Validators.required,
Validators.minLength(3),
Validators.maxLength(50)]],
tags: this.fb.array([]),
description: ''
});
// Read the product Id from the route parameter
this.sub = this.route.paramMap.subscribe(
params => {
const id = +params.get('id');
this.getProduct(id);
}
);
}
getProduct(id: number): void {
this.productService.getProduct(id)
.subscribe(
(product: Product) => this.displayProduct(product),
(error: any) => this.errorMessage = <any>error
);
}
displayProduct(product: Product): void {
if (this.productForm) {
this.productForm.reset();
}
this.product = product;
// Update the data on the form
this.productForm.patchValue({
productName: this.product.productName,
description: this.product.description
});
this.productForm.setControl('tags', this.fb.array(this.product.tags || []));
}
Let me know if you have any questions about either example.
I totally agree with the recommendations made by @DeborahK in the previous answer and you should follow those while using Reactive forms.
However, those are not the reason for your error. In your HTML template, you have a wrong hierarchy of your FormArray
control. It should be FormArray --> FormGroup --> FormControl, like this:
<div class="row"
formArrayName="ingredients"
*ngFor="let ctrl of recipeform.get('ingredients').controls;let i=index"
style="margin-top: 10px;">
<div [formGroupName]="i">
<div class="col-xs-8">
<input type="text"
formControlName="name"
class="form-control">
</div>
<div class="col-xs-2">
<input type="number"
class="form-control"
formControlName="amount">
</div>
<div class="col-xs-2">
<button type="button"
class="btn btn-danger">
X
</button>
</div>
</div>
</div>
As you can see, I have wrapped the name and amount control within a div
and moved the [formGroupName]
to this wrapper div. I didn't test the code but it should solve your problem.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.