You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular动态嵌套FormArray无法正常工作问题求助

Angular嵌套FormArray报错:Cannot find control with path: 'books -> 0 -> authors -> 0'

我正在学习Angular,想要实现一个可添加/删除的书籍数组,每本书对应一个同样可添加/删除的作者数组,但一直遇到错误:Cannot find control with path: 'books -> 0 -> authors -> 0'

TS代码

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

/**
 * @title Stepper that displays errors in the steps
 */
@Component({
  selector: 'app-home',
  templateUrl: 'home.component.html',
  styleUrls: ['home.component.scss'],
  providers: [
    {
      provide: STEPPER_GLOBAL_OPTIONS,
      useValue: {showError: true},
    },
  ],
})
export class HomeComponent implements OnInit {

  bookForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.bookForm = this.fb.group({
      books: this.fb.array([])  // Create an empty FormArray for books
    });
  }

  ngOnInit(): void {
      this.createBook()
  }

  get books() {
    return this.bookForm.get('books') as FormArray;
  }

  addBook() {
    this.books.push(this.createBook());
  }

  removeBook(index: number) {
    this.books.removeAt(index);
  }

  createBook() {
    return this.fb.group({
      title: ['', Validators.required],
      authors: this.fb.array([this.createAuthor()])  // Initialize with an empty author control
    });
  }
  
  createAuthor() {
    return this.fb.control('', Validators.required);
  }
  
  

  getAuthors(bookIndex: number) {
    return this.books.at(bookIndex).get('authors') as FormArray;
  }

  addAuthor(bookIndex: number) {
    const book = this.books.at(bookIndex) as FormGroup;
    const authors = book.get('authors') as FormArray;
    authors.push(this.createAuthor());
  }
  
  removeAuthor(bookIndex: number, authorIndex: number) {
    const book = this.books.at(bookIndex) as FormGroup;
    const authors = book.get('authors') as FormArray;
    authors.removeAt(authorIndex);
  }
  
  onSubmit() {
    if (this.bookForm.valid) {
      // Handle form submission
      console.log(this.bookForm.value);
    }
  }
 
}

HTML代码

<form [formGroup]="bookForm" (ngSubmit)="onSubmit()">
    <div formArrayName="books">
      <div *ngFor="let book of books.controls; let bookIndex = index">
        <div [formGroupName]="bookIndex">
          <div>
            <label>
              Book Title:
              <input formControlName="title">
            </label>
            <button type="button" (click)="removeBook(bookIndex)">Remove Book</button>
          </div>
          <div formArrayName="authors">
            <div *ngFor="let author of getAuthors(bookIndex).controls; let authorIndex = index">
              <div [formGroupName]="authorIndex">
                <label>
                  Author:
                  <input formControlName="authorName">
                </label>
                <button type="button" (click)="removeAuthor(bookIndex, authorIndex)">Remove Author</button>
              </div>
            </div>
            <button type="button" (click)="addAuthor(bookIndex)">Add Author</button>
          </div>
        </div>
      </div>
      <button type="button" (click)="addBook()">Add Book</button>
    </div>
    <button type="submit">Submit</button>
  </form>

问题原因与修复方案

核心问题

报错的根源是表单结构与模板绑定不匹配:

  1. TS中createAuthor()返回的是单个FormControl,但HTML中却用了[formGroupName]="authorIndex"——这个指令只适用于FormGroup类型的控件,不能绑定到FormControl。
  2. HTML中input的formControlName="authorName"无效,因为authors数组里的元素是单个控件,不存在authorName这个键。
  3. ngOnInit中仅调用createBook(),但未将创建的书籍表单组添加到books数组,导致初始时数组为空,触发绑定错误。

修复步骤

方案1:保持作者为单个FormControl(字符串)

修改HTML中作者循环部分的模板,去掉[formGroupName],直接绑定到FormControl:

<div formArrayName="authors">
  <div *ngFor="let author of getAuthors(bookIndex).controls; let authorIndex = index">
    <label>
      Author:
      <input [formControl]="author">
    </label>
    <button type="button" (click)="removeAuthor(bookIndex, authorIndex)">Remove Author</button>
  </div>
  <button type="button" (click)="addAuthor(bookIndex)">Add Author</button>
</div>

同时修正ngOnInit,将初始书籍添加到数组:

ngOnInit(): void {
  this.books.push(this.createBook());
}

方案2:将作者改为带字段的FormGroup(推荐,更灵活)

如果希望作者数据是包含authorName的对象,修改TS中的createAuthor()方法:

createAuthor() {
  return this.fb.group({
    authorName: ['', Validators.required]
  });
}

此时原HTML模板的[formGroupName]="authorIndex"和formControlName="authorName"可以正常使用,只需修正ngOnInit的数组添加逻辑即可。

内容的提问来源于stack exchange,提问作者Joe EnDo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 11:21:06