Angular 6嵌套动态表单报错:Cannot find control with path: 'ingredients -> 0 -> 0'
解决Angular 6嵌套FormArray动态输入表单错误
我来帮你排查这个问题,控制台报错Cannot find control with path: 'ingredients -> 0 -> 0'主要是HTML模板里的表单控件路径绑定错误,再加上TS里的几个小拼写问题,咱们一步步解决:
问题分析与修复步骤
1. HTML模板重复绑定formGroupName
你的代码里在<div *ngFor>外层已经用了[formGroupName]="i",但里面又嵌套了一个同样的[formGroupName]="i",这会让Angular试图去寻找ingredients[0][0]这个不存在的控件——实际上每个ingredients数组元素是一个FormGroup,里面只有newIngredient这个表单控件,不需要再嵌套一层索引绑定。
2. TS方法里的表单控件名称拼写错误
addIngredient方法里你写的是this.recipeForm.get('ingredient'),但实际表单数组的名称是ingredients(复数);addInstruction同理,应该是instructions而不是instruction。
3. 按钮事件绑定错误
HTML里的按钮用了(onclick),Angular里正确的点击事件绑定是(click)。
4. 优化:直接获取FormArray的方式
你可以在组件里添加一个快捷方法来获取ingredients数组,避免模板里写recipeForm.get('ingredients')['controls']这种冗长的写法。
修复后的完整代码
HTML模板
<div formArrayName="ingredients"> <div *ngFor="let ingredient of ingredients.controls; let i=index" [formGroupName]="i"> <div> <span>Zutat {{i + 1}}</span> <span *ngIf="ingredients.length > 1" (click)="removeIngredient(i)" class="btn btn-danger"> 删除 </span> </div> <div class="form-group col-xs-6"> <input type="text" class="form-control" formControlName="newIngredient"> </div> </div> <div class="btn btn-success" (click)="addIngredient()">neue Zutat</div> </div> <!-- 同理处理instructions部分 --> <div formArrayName="instructions"> <div *ngFor="let instruction of instructions.controls; let i=index" [formGroupName]="i"> <div> <span>Anweisung {{i + 1}}</span> <span *ngIf="instructions.length > 1" (click)="removeInstruction(i)" class="btn btn-danger"> 删除 </span> </div> <div class="form-group col-xs-12"> <input type="text" class="form-control" formControlName="newInstruction"> </div> </div> <div class="btn btn-success" (click)="addInstruction()">neue Anweisung</div> </div>
TS组件代码
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, FormArray } from '@angular/forms'; import { NewRecipe } from '../recipe.interface'; @Component({ selector: 'app-recipe-creator', templateUrl: './recipe-creator.component.html', styleUrls: ['./recipe-creator.component.css'] }) export class RecipeCreatorComponent implements OnInit { recipeForm: FormGroup; constructor(private formBuilder: FormBuilder) {} ngOnInit() { this.recipeForm = this.formBuilder.group({ name: '', category: '', prep_time: 0, cooking_time: 0, price: 0, ingredients: this.formBuilder.array([this.createIngredient()]), instructions: this.formBuilder.array([this.createInstruction()]) }); } // 快捷获取ingredients FormArray get ingredients(): FormArray { return this.recipeForm.get('ingredients') as FormArray; } // 快捷获取instructions FormArray get instructions(): FormArray { return this.recipeForm.get('instructions') as FormArray; } createIngredient(): FormGroup { return this.formBuilder.group({ newIngredient: [''] }); } createInstruction(): FormGroup { return this.formBuilder.group({ newInstruction: [''] }); } addIngredient(): void { this.ingredients.push(this.createIngredient()); } addInstruction(): void { this.instructions.push(this.createInstruction()); } removeIngredient(index: number): void { this.ingredients.removeAt(index); } removeInstruction(index: number): void { this.instructions.removeAt(index); } saveRecipe() { // 这里可以处理表单提交逻辑,比如打印表单值 console.log(this.recipeForm.value); } }
Angular 6 FormArray核心使用要点(替代外部教程)
如果你是Angular 6新手,记住这几个核心点就能搞定动态表单:
- FormArray是FormGroup的一种特殊类型,用来管理一组同结构的表单控件/组,必须通过
formBuilder.array()初始化。 - 模板绑定顺序:先写
formArrayName="数组名",然后用*ngFor遍历数组的controls,给每个元素绑定[formGroupName]="索引"(如果数组元素是FormGroup)。 - 快捷获取FormArray:用组件的getter方法(比如上面的
get ingredients()),让模板代码更简洁易维护。 - 增删操作:用FormArray的
push()添加新元素,removeAt(索引)删除指定位置元素,clear()清空整个数组。 - 表单验证:如果需要给动态控件加验证,直接在
createIngredient()这类方法里给FormControl添加验证器,比如newIngredient: ['', Validators.required]。
内容的提问来源于stack exchange,提问作者RickyHoliday
相关产品推荐
相关产品推荐

